67 votes

Peut-on convertir un objet générique en un type d'objet personnalisé en javascript ?

Par exemple, j'ai déjà cet objet quelque part dans le code, c'est un objet générique :

var person1={lastName:"Freeman",firstName:"Gordon"};

J'ai le constructeur d'un objet Personne :

function Person(){
 this.getFullName=function(){
  return this.lastName + ' ' + this.firstName;
 }
}

Existe-t-il une syntaxe simple qui nous permette de convertir person1 en un objet de type Person ?

11 votes

Il n'y a pas de casting en JavaScript donc ... la réponse courte est non. La réponse plus longue est ... toujours non. En effet, le [[prototype]] ne peut être défini que lorsqu'un objet est créé. Cependant, il est possible de copier les méthodes/propriétés de Person vers person1, ce qui est une approche utilisée par certains "class frameworks" de toute façon. Je me contenterais probablement de créer un nouveau Personne de personne1 dans un "copieur-constructeur".

59voto

A1rPun Points 2995

La réponse de @PeterOlson a peut-être fonctionné à l'époque mais il semble que Object.create a changé. J'opterais pour la méthode de la copie-constructeur comme l'a dit @user166390 dans les commentaires.
La raison pour laquelle j'ai nécromancé ce post est que j'avais besoin d'une telle mise en œuvre.

Aujourd'hui, nous pouvons utiliser Object.assign ( crédits à la solution @SayanPal ) et la syntaxe ES6 :

class Person {
  constructor(obj) {
    obj && Object.assign(this, obj);
  }

  getFullName() {
    return `${this.lastName} ${this.firstName}`;
  }
}

Utilisation :

const newPerson = new Person(person1)
newPerson.getFullName() // -> Freeman Gordon

Réponse ES5 ci-dessous

function Person(obj) {
    for(var prop in obj){
        // for safety you can use the hasOwnProperty function
        this[prop] = obj[prop];
    }
}

Utilisation :

var newPerson = new Person(person1);
console.log(newPerson.getFullName()); // -> Freeman Gordon

En utilisant une version plus courte, 1.5 liner :

function Person(){
    if(arguments[0]) for(var prop in arguments[0]) this[prop] = arguments[0][prop];
}

jsfiddle

2 votes

Bravo pour la version "1.5 liner", j'adore.

0 votes

Mais cette réponse revient en fait à écrire le extend les fonctions de la plupart des cadres ont là-dedans... Et Object.assign est le remplaçant de cette fonction... A ce jour, seuls Internet Explorer et Safari <= 9 ne la supportent pas. Ce que je ferais, c'est prendre un Polyfill Object.assign et l'utiliser lorsque le véritable Object.assign n'est pas présent. Dans mon projet, j'ai un morceau de code qui vérifie les fonctionnalités nécessaires et qui, si l'une d'entre elles est manquante, charge un second script contenant des polyfills pour ces fonctionnalités.

0 votes

@StijndeWitt Je suis d'accord avec l'utilisation de Object.assign sur cette solution. Voir la solution de @SayanPal qui utilise la méthode assign. Je mettrai à jour cette réponse un jour ;)

12voto

Peter Olson Points 30452

Vous pourriez utiliser Objet.create [MDN] :

newPerson = Object.create(Person, person1);

8voto

Adam Rackis Points 45559

Non.

Mais si vous cherchez à traiter votre person1 comme s'il s'agissait d'un Person vous pouvez appeler des méthodes sur Person Le prototype de l'entreprise sur person1 con call :

Person.prototype.getFullNamePublic = function(){
    return this.lastName + ' ' + this.firstName;
}
Person.prototype.getFullNamePublic.call(person1);

Bien que cela ne fonctionne évidemment pas pour les méthodes privilégiées créées à l'intérieur du constructeur de la personne - comme votre getFullName méthode.

7voto

Sayan Pal Points 2347

Il ne s'agit pas exactement d'une réponse, mais plutôt de partager mes résultats et d'espérer obtenir des arguments critiques pour ou contre, car je ne suis pas conscient de son efficacité.

J'ai récemment eu besoin de faire cela pour mon projet. Je l'ai fait en utilisant Object.assign Plus précisément, cela se passe de la manière suivante : Object.assign(new Person(...), anObjectLikePerson) .

Voici le lien vers mon JSFiddle et aussi la partie principale du code :

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;

  this.getFullName = function() {
    return this.lastName + ' ' + this.firstName;
  }
}

var persons = [{
  lastName: "Freeman",
  firstName: "Gordon"
}, {
  lastName: "Smith",
  firstName: "John"
}];

var stronglyTypedPersons = [];
for (var i = 0; i < persons.length; i++) {
  stronglyTypedPersons.push(Object.assign(new Person("", ""), persons[i]));
}

0 votes

Cette syntaxe est très agréable et efficace. C'est probablement la meilleure façon de procéder. Dommage que certains navigateurs ne le supportent pas encore. .

1 votes

@A1rPun pollyfill peut être utilisé dans ces cas : kangax.github.io/compat-table/es6/

1 votes

C'est la meilleure réponse. Les différences entre assign() et create() sont les suivantes : 1) assign fonctionne avec des propriétés qui ne sont pas des objets ; 2) assign ignore les propriétés inconnues.

2voto

pasx Points 141

Il s'agit simplement d'un résumé de la réponse de Sayan Pal sous une forme plus courte, dans le style ES5 :

var Foo = function(){
    this.bar = undefined;
    this.buzz = undefined;
}

var foo = Object.assign(new Foo(),{
    bar: "whatever",
    buzz: "something else"
});

Je l'aime parce qu'il est le plus proche de l'initialisation d'objet très soignée de .Net :

var foo = new Foo()
{
    bar: "whatever",
    ...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X