Extension d'un objet en Javascript


164

Je suis actuellement en train de passer de Java à Javascript, et il m'est un peu difficile de comprendre comment étendre les objets comme je le souhaite.

J'ai vu plusieurs personnes sur Internet utiliser une méthode appelée extension sur objet. Le code ressemblera à ceci:

var Person = {
   name : 'Blank',
   age  : 22
}

var Robot = Person.extend({
   name : 'Robo',
   age  : 4
)}

var robot = new Robot();
alert(robot.name); //Should return 'Robo'

Quelqu'un sait-il comment faire fonctionner cela? J'ai entendu dire que tu devais écrire

Object.prototype.extend = function(...);

Mais je ne sais pas comment faire fonctionner ce système. Si ce n'est pas possible, veuillez me montrer une autre alternative qui étend un objet.


retourne vrai; mais c'est pourquoi je demande :)
Wituz

2
je suggérerais de parcourir ce magnifique tutoriel sur MDN: - developer.mozilla.org/en/...
Pranav

Si après avoir lu ces bons documents, vous êtes toujours curieux d'une extendfonction, j'ai mis en place un exemple ici: jsfiddle.net/k9LRd
Codrin Eugeniu

2
Je suggérerais également de ne pas y penser strictement comme `` passer de Java à JavaScript '' et plus comme `` apprendre un nouveau langage, Javascript, qui a une syntaxe similaire à Java ''
Toni Leigh

Réponses:


195

Vous voulez 'hériter' de l'objet prototype de Person:

var Person = function (name) {
    this.name = name;
    this.type = 'human';
};

Person.prototype.info = function () {
    console.log("Name:", this.name, "Type:", this.type);
};

var Robot = function (name) {
    Person.apply(this, arguments);
    this.type = 'robot';
};

Robot.prototype = Person.prototype;  // Set prototype to Person's
Robot.prototype.constructor = Robot; // Set constructor back to Robot

person = new Person("Bob");
robot = new Robot("Boutros");

person.info();
// Name: Bob Type: human

robot.info();
// Name: Boutros Type: robot

4
J'ai une question: comment le Person()constructeur est-il appelé lorsque vous le faites new Robot()? Il me semble que vous devriez appeler ce constructeur de classe de base au lieu de le faire this.name = name;dans le Robot()constructeur ...
Alexis Wilke

21
@AlexisWilke: Oui, vous devriez appeler Person.apply(this, arguments);. Il serait également préférable d'utiliser Robot.prototype = Object.create(Person.prototype);au lieu de new Person();.
Felix Kling

18
Comme indiqué par Felix, 'Robot.prototype = Person.prototype;' est une mauvaise idée si quelqu'un souhaite que le type 'Robot' ait sa propre instance de prototype. L'ajout de nouvelles fonctions spécifiques au Robot l'ajouterait également à la personne.
James Wilkins

20
Cet exemple est complètement faux. En faisant cela, vous modifiez le prototype de Person. Ce n'est pas un héritage et vous risquez de mettre un énorme gâchis dans la classe Person. Voir la réponse qui recommande d'utiliser Object.create (). C'est la bonne façon de faire les choses.
nicolas-van

6
@osahyoun cette réponse a un haut rang dans la recherche de Google. Je vous suggère vraiment de corriger le code et de corriger la chaîne de prototypes comme suggéré par d'autres commentaires ici.
raphaëλ

103

Monde sans le mot-clé «nouveau».

Et une syntaxe plus simple de type "prose" avec Object.create ().

* Cet exemple est mis à jour pour les classes ES6.

Tout d'abord, rappelez-vous que Javascript est un langage prototypique . Ce n'est pas basé sur la classe. Par conséquent, l'écriture sous forme prototypique expose sa vraie nature et peut être très simple, semblable à une prose et puissante.

TLDR;

const Person = { name: 'Anonymous' } // person has a name

const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'

Non, vous n'avez pas besoin de constructeurs, pas d' newinstanciation ( lisez pourquoi vous ne devriez pas utilisernew ), non super, pas de drôle de drôle __construct. Vous créez simplement des objets, puis les étendez ou les transformez.

( Si vous connaissez les getters et les setters, consultez la section "Lectures supplémentaires" pour voir comment ce modèle vous donne des getters et des setters gratuits comme Javascript l'avait initialement prévu, et à quel point ils sont puissants .)

Syntaxe de type prose: Protoype de base

const Person = {

   //attributes
   firstName : 'Anonymous', 
   lastName: 'Anonymous',
   birthYear  : 0,
   type : 'human',

   //methods
   name() { return this.firstName + ' ' + this.lastName },
   greet() {
       console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' )
   },
   age() {
      // age is a function of birth time.
   }
}

const person = Object.create(Person). // that's it!

En un coup d'œil, semble très lisible.

Extension, création d'un descendant de Person

* Les termes corrects sont prototypes, et leur descendants. Il n'y a pas classeset pas besoin de instances.

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'

const anakin = Object.create(Skywalker)
anakin.firstName = 'Anakin'
anakin.birthYear = '442 BBY'
anakin.gender = 'male' // you can attach new properties.
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Person.isPrototypeOf(Skywalker) // outputs true
Person.isPrototypeOf(anakin) // outputs true
Skywalker.isPrototypeOf(anakin) // outputs true

Une façon de fournir un moyen "par défaut" de créer un descendant, est de joindre une #createméthode:

Skywalker.create = function(firstName, gender, birthYear) {

    let skywalker = Object.create(Skywalker)

    Object.assign(skywalker, {
        firstName,
        birthYear,
        gender,
        lastName: 'Skywalker',
        type: 'human'
    })

    return skywalker
}

const anakin = Skywalker.create('Anakin', 'male', '442 BBY')

Les moyens ci-dessous ont une lisibilité inférieure:

Comparer à l'équivalent "classique":

function Person (firstName, lastName, birthYear, type) {
    this.firstName = firstName 
    this.lastName = lastName
    this.birthYear = birthYear
    this.type = type
}

// attaching methods
Person.prototype.name = function() { return firstName + ' ' + lastName }
Person.prototype.greet = function() { ... }
Person.prototype.age = function() { ... }

function Skywalker(firstName, birthYear) {
    Person.apply(this, [firstName, 'Skywalker', birthYear, 'human'])
}

// confusing re-pointing...
Skywalker.prototype = Person.prototype
Skywalker.prototype.constructor = Skywalker

const anakin = new Skywalker('Anakin', '442 BBY')

Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns false!

La lisibilité du code en utilisant un style "classique" n'est pas très bonne.

Classes ES6

Certes, certains de ces problèmes sont éradiqués par les classes ES6, mais quand même:

class Person {
    constructor(firstName, lastName, birthYear, type) {
        this.firstName = firstName 
        this.lastName = lastName
        this.birthYear = birthYear
        this.type = type
    }
    name() { return this.firstName + ' ' + this.lastName }
    greet() { console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' ) }
}

class Skywalker extends Person {
    constructor(firstName, birthYear) {
        super(firstName, 'Skywalker', birthYear, 'human')
    }
}

const anakin = new Skywalker('Anakin', '442 BBY')

// prototype chain inheritance checking is partially fixed.
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns true

Branchement du prototype de base

// create a `Robot` prototype by extending the `Person` prototype:
const Robot = Object.create(Person)
Robot.type = 'robot'
Robot.variant = '' // add properties for Robot prototype

Joindre des méthodes uniques à Robot

// Robots speak in binaries, so we need a different greet function:
Robot.machineGreet = function() { /*some function to convert strings to binary */ }

// morphing the `Robot` object doesn't affect `Person` prototypes
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'
anakin.machineGreet() // error

Vérification de l'héritage

Person.isPrototypeOf(Robot) // outputs true
Robot.isPrototypeOf(Skywalker) // outputs false

Vous avez déjà tout ce dont vous avez besoin! Pas de constructeur, pas d'instanciation. Prose propre et claire.

Lectures complémentaires

Écriture, configurabilité et Getters et Setters gratuits!

Pour les getters et les setters gratuits, ou pour une configuration supplémentaire, vous pouvez utiliser le deuxième argument d'Object.create () aka propertiesObject. Il est également disponible dans # Object.defineProperty et # Object.defineProperties .

Pour illustrer à quel point cela est puissant, supposons que nous voulions tous Robotêtre strictement faits de métal (via writable: false) et normaliser les powerConsumptionvaleurs (via des getters et des setters).

const Robot = Object.create(Person, {
    // define your property attributes
    madeOf: { 
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    // getters and setters, how javascript had (naturally) intended.
    powerConsumption: {
        get() { return this._powerConsumption },
        set(value) { 
            if (value.indexOf('MWh')) return this._powerConsumption = value.replace('M', ',000k') 
            this._powerConsumption = value
            throw new Error('Power consumption format not recognised.')
        }  
    }
})

const newRobot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

Et tous les prototypes de Robotne peuvent pas être madeOfautre chose parce que writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

console.log(polymerRobot.madeOf) // outputs 'metal'

Mixins (en utilisant # Object.assign) - Anakin Skywalker

Pouvez-vous sentir où cela va ...?

const darthVader = Object.create(anakin)
// for brevity, property assignments are skipped because you get the point by now.

Object.assign(darthVader, Robot)

Dark Vador obtient les méthodes de Robot:

darthVader.greet() // inherited from `Person`, outputs "Hi, my name is Darth Vader..."
darthVader.machineGreet() // inherited from `Robot`, outputs 001010011010...

Avec d'autres choses étranges:

console.log(darthVader.type) // outputs robot.
Robot.isPrototypeOf(darthVader) // returns false.
Person.isPrototypeOf(darthVader) // returns true.

Eh bien, que Dark Vador soit un homme ou une machine est en effet subjectif:

«Il est plus une machine maintenant qu'un homme, tordu et méchant. - Obi Wan Kenobi

"Je sais qu'il y a du bien en toi." - Luke Skywalker

Extra - Syntaxe légèrement plus courte avec # Object.assign

Selon toute vraisemblance, ce modèle raccourcit votre syntaxe. Mais ES6 # Object.assign peut raccourcir un peu plus (pour polyfill à utiliser sur les navigateurs plus anciens, voir MDN sur ES6 ).

//instead of this
const Robot = Object.create(Person)
Robot.name = "Robot"
Robot.madeOf = "metal"

//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
    name: "Robot",
    madeOf: "metal"
    // for brevity, you can imagine a long list will save more code.
})

8
avoir un vote positif pour ne pas utiliser de fonction constructeur.
nsmarks

1
programmeurs "de formation classique", qu'entendez-vous par là?
Petra

1
Je viens d'un état d'esprit OOP classique et cette réponse m'a beaucoup aidé. Deux questions sur le code: 1) todays ES2015 est-il Object.assign(Robot, {a:1}une bonne alternative à votre extend()méthode? 2) Comment remplacer la greet()méthode pour qu'elle renvoie le même texte, mais avec "un remplacement de salutation" ajouté?
Barry Staes

2
1) #Object.assignsemble être une bonne alternative. Mais la prise en charge du navigateur est inférieure à atm. 2) Vous utiliserez la __proto__propriété de l'objet pour accéder à la fonction de salutation de son prototype. alors vous appelez la fonction de salutation de prototype avec la portée de l'appelé passée. Dans ce cas, la fonction était un journal de console, il n'est donc pas possible d '«ajouter». Mais avec cet exemple, je pense que vous obtenez la dérive. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr

1
Eh bien, c'est une discussion qui devrait avoir lieu avec les responsables de la spécification du langage ECMAScript. Je suis généralement d'accord, mais je dois travailler avec ce que j'ai.

51

Si vous n'avez pas encore trouvé de moyen, utilisez la propriété associative des objets JavaScript pour ajouter une fonction d'extension au Object.prototypecomme indiqué ci-dessous.

Object.prototype.extend = function(obj) {
   for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
         this[i] = obj[i];
      }
   }
};

Vous pouvez ensuite utiliser cette fonction comme indiqué ci-dessous.

var o = { member: "some member" };
var x = { extension: "some extension" };

o.extend(x);

18
Attention, cela créera des pointeurs vers l'objet d'origine dans la classe «enfant» lors de l'utilisation d'objets / tableaux dans la classe «parent». Pour élaborer: Si vous avez un objet ou un tableau dans votre classe parent, le modifier dans une classe enfant qui s'étend sur cette base, le modifiera en fait pour toutes les classes enfants qui s'étendent sur cette même classe de base.
Harold

Harold, Merci d'avoir souligné ce fait. Il est important pour quiconque utilise la fonction d'incorporer une condition qui vérifie les objets / tableaux et en fait des copies.
dimanche

30

Approche différente: Object.create

Selon la réponse @osahyoun, je trouve ce qui suit comme un moyen meilleur et efficace d'`` hériter '' de l'objet prototype de Person:

function Person(name){
    this.name = name;
    this.type = 'human';
}

Person.prototype.info = function(){
    console.log("Name:", this.name, "Type:", this.type);
}

function Robot(name){
    Person.call(this, name)
    this.type = 'robot';
}

// Set Robot's prototype to Person's prototype by
// creating a new object that inherits from Person.prototype,
// and assigning it to Robot.prototype
Robot.prototype = Object.create(Person.prototype);

// Set constructor back to Robot
Robot.prototype.constructor = Robot;

Créez de nouvelles instances:

var person = new Person("Bob");
var robot = new Robot("Boutros");

person.info(); // Name: Bob Type: human
robot.info();  // Name: Boutros Type: robot

Maintenant, en utilisant Object.create :

Person.prototype.constructor !== Robot

Consultez également la documentation MDN .


2
Je veux juste dire @GaretClaborn que cela fonctionne correctement, mais vous ne passez pas le nameparamètre au constructeur parent, comme ceci: jsfiddle.net/3brm0a7a/3 (la différence est dans la ligne # 8)
xPheRe

1
@xPheRe Ah je vois, merci. J'ai modifié la réponse pour refléter ce changement
Garet Claborn

1
@xPheRe, je suppose que j'étais plus concentré sur le fait de prouver un point lorsque j'ai ajouté cette solution. Merci.
Lior Elrom

1
Belle réponse +1, vous pouvez jeter un oeil à ECMAScript 6. La classe de mots-clés et étend est disponible: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Benjamin Poignant

26

Dans ES6 , vous pouvez utiliser un opérateur de diffusion comme

var mergedObj = { ...Obj1, ...Obj2 };

Notez que Object.assign () déclenche des setters alors que la syntaxe de diffusion ne le fait pas.

Pour plus d'informations, voir le lien MDN -Spread Syntax


Ancienne réponse:

Dans ES6 , il y a Object.assignpour copier les valeurs de propriété. Utilisez {}comme premier paramètre si vous ne souhaitez pas modifier l'objet cible (le premier paramètre est passé).

var mergedObj = Object.assign({}, Obj1, Obj2);

Pour plus de détails, voir lien, MDN - Object.assign ()

Si vous avez besoin d'un Polyfill pour ES5 , le lien le propose également. :)


18

Et un an plus tard, je peux vous dire qu'il y a une autre bonne réponse.

Si vous n'aimez pas la façon dont le prototypage fonctionne pour s'étendre sur des objets / classes, jetez un œil à ceci: https://github.com/haroldiedema/joii

Exemple de code rapide des possibilités (et bien d'autres):

var Person = Class({

    username: 'John',
    role: 'Employee',

    __construct: function(name, role) {
        this.username = name;
        this.role = role;
    },

    getNameAndRole: function() {
        return this.username + ' - ' + this.role;
    }

});

var Manager = Class({ extends: Person }, {

  __construct: function(name)
  {
      this.super('__construct', name, 'Manager');
  }

});

var m = new Manager('John');
console.log(m.getNameAndRole()); // Prints: "John - Manager"

Eh bien, il me reste encore 2 mois avant la fin des 2 ans: P Quoi qu'il en soit, JOII 3.0 est sur le point de sortir :)
Harold

1
Faites cela 3 ans plus tard.

Concept intéressant, mais la syntaxe semble vraiment moche. Vous feriez mieux d'attendre que les cours ES6 deviennent stables
sleepycal

Je suis entièrement d'accord @sleepycal. Mais malheureusement, il faudra encore au moins 5 ans avant que tous les navigateurs majeurs / courants aient mis en œuvre cela. Donc, en attendant, cela devra faire ...
Harold

12

Les personnes qui luttent encore pour la meilleure approche simple, vous pouvez utiliser Spread Syntaxpour étendre l'objet.

var person1 = {
      name: "Blank",
      age: 22
    };

var person2 = {
      name: "Robo",
      age: 4,
      height: '6 feet'
    };
// spread syntax
let newObj = { ...person1, ...person2 };
console.log(newObj.height);

Remarque: n'oubliez pas que la propriété la plus à droite aura la priorité. Dans cet exemple, person2est à droite, donc newObjaura le nom Robo dedans.



6

Mozilla 'annonce' un objet s'étendant d'ECMAScript 6.0:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends

REMARQUE: Il s'agit d'une technologie expérimentale faisant partie de la proposition ECMAScript 6 (Harmony).

class Square extends Polygon {
  constructor(length) {
    // Here, it calls the parent class' constructor with lengths
    // provided for the Polygon's width and height
    super(length, length);
    // Note: In derived classes, super() must be called before you
    // can use 'this'. Leaving this out will cause a reference error.
    this.name = 'Square';
  }

  get area() {
    return this.height * this.width;
  }

  set area(value) {
    this.area = value;     } 
}

Cette technologie est disponible dans Gecko (Google Chrome / Firefox) - versions nocturnes 03/2015.


4

Dans la majorité des projets, il existe une implémentation de l'extension d'objet: soulignement, jquery, lodash: extend .

Il existe également une implémentation javascript pure, qui fait partie d'ECMAscript 6: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


L'expression «implémentation javascript pure» ne fait-elle pas référence à quelque chose qui est implémenté uniquement avec JavaScript, pas à une fonction fournie par l'environnement qui pourrait être implémentée de manière native?
binki

1
@binki, je voulais dire implémentation native de javascript - partie de la norme ECMAScript 2015 (ES6)
Cezary Daniel Nowak

2
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Ensuite:

function Person() {
    this.name = "anonym"
    this.skills = ["abc"];
}
Person.prototype.profile = function() {
    return this.skills.length // 1
};

function Student() {} //well extends fom Person Class
Student.extends(Person)

var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

Mise à jour 01/2017:

S'il vous plaît, ignorez ma réponse de 2015 car Javascript est maintenant compatible avec le extendsmot-clé depuis ES6 (Ecmasctipt6)

- ES6:

class Person {
   constructor() {
     this.name = "anonym"
     this.skills = ["abc"];
   }

   profile() {
    return this.skills.length // 1
   }

}

Person.MAX_SKILLS = 10;
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

- ES7:

class Person {
    static MAX_SKILLS = 10;
    name = "anonym"
    skills = ["abc"];

    profile() {
      return this.skills.length // 1
    }

}
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

1
En appelant new ParentClass()avant d'écraser le constructeur, vous avez déjà exécuté le constructeur parent. Je ne pense pas que ce soit un comportement correct si vous me demandez ...
Harold

1

Résumé:

Javascript utilise un mécanisme appelé héritage prototypique . L'héritage prototypique est utilisé lors de la recherche d'une propriété sur un objet. Lorsque nous étendons des propriétés en javascript, nous héritons de ces propriétés d'un objet réel. Cela fonctionne de la manière suivante:

  1. Lorsqu'une propriété d'objet est demandée, (par exemple myObj.fooou myObj['foo']) le moteur JS recherchera d'abord cette propriété sur l'objet lui-même
  2. Lorsque cette propriété n'est pas trouvée sur l'objet lui-même, elle escaladera la chaîne de prototypes en regardant l'objet prototype. Si cette propriété n'est pas non plus trouvée ici, elle continuera à gravir la chaîne du prototype jusqu'à ce que la propriété soit trouvée. Si la propriété n'est pas trouvée, une erreur de référence sera générée.

Lorsque nous voulons étendre un objet en javascript, nous pouvons simplement lier cet objet dans la chaîne de prototypes. Il existe de nombreuses façons d'y parvenir, je décrirai 2 méthodes couramment utilisées.

Exemples:

1. Object.create()

Object.create()est une fonction qui prend un objet comme argument et crée un nouvel objet. L'objet qui a été passé en argument sera le prototype de l'objet nouvellement créé. Par exemple:

// prototype of the dog
const dogPrototype = {
  woof: function () { console.log('woof'); }
}

// create 2 dog objects, pass prototype as an argument
const fluffy = Object.create(dogPrototype);
const notFluffy = Object.create(dogPrototype);

// both newly created object inherit the woof 
// function from the dogPrototype
fluffy.woof();
notFluffy.woof();

2. Définition explicite de la propriété prototype

Lors de la création d'objets à l'aide de fonctions de constructeur, nous pouvons définir des propriétés d'ajout à sa propriété d'objet prototype. Les objets créés forment une fonction de constructeur lors de l'utilisation du newmot - clé, ont leur prototype défini sur le prototype de la fonction de constructeur. Par exemple:

// Constructor function object
function Dog (name) {
   name = this.name;
}

// Functions are just objects
// All functions have a prototype property
// When a function is used as a constructor (with the new keyword)
// The newly created object will have the consturctor function's
// prototype as its prototype property
Dog.prototype.woof = function () {
  console.log('woof');
}

// create a new dog instance
const fluffy = new Dog('fluffyGoodBoyyyyy');
// fluffy inherits the woof method
fluffy.woof();

// can check the prototype in the following manner
console.log(Object.getPrototypeOf(fluffy));


0

Vous pouvez simplement le faire en utilisant:

Object.prototype.extend = function(object) {
  // loop through object 
  for (var i in object) {
    // check if the extended object has that property
    if (object.hasOwnProperty(i)) {
      // mow check if the child is also and object so we go through it recursively
      if (typeof this[i] == "object" && this.hasOwnProperty(i) && this[i] != null) {
        this[i].extend(object[i]);
      } else {
        this[i] = object[i];
      }
    }
  }
  return this;
};

mise à jour: j'ai vérifié this[i] != nullcar nullest un objet

Ensuite, utilisez-le comme:

var options = {
      foo: 'bar',
      baz: 'dar'
    }

    var defaults = {
      foo: false,
      baz: 'car',
      nat: 0
    }

defaults.extend(options);

Ce bien aboutit à:

// defaults will now be
{
  foo: 'bar',
  baz: 'dar',
  nat: 0
}

0

S'IL VOUS PLAÎT AJOUTER LA RAISON DU DOWNVOTE

  • Pas besoin d'utiliser une bibliothèque externe pour étendre

  • En JavaScript, tout est un objet (à l'exception des trois types de données primitifs, et même ils sont automatiquement enveloppés d'objets en cas de besoin). De plus, tous les objets sont mutables.

Personne de classe en JavaScript

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    getName: function() {
        return this.name;
    },
    getAge: function() {
        return this.age;
    }
}

/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);

Modifiez une instance / un objet spécifique .

alice.displayGreeting = function() 
{
    alert(this.getGreeting());
}

Modifier la classe

Person.prototype.getGreeting = function() 
{
    return 'Hi ' + this.getName() + '!';
};

Ou dites simplement: étendre JSON et OBJECT sont les mêmes

var k = {
    name : 'jack',
    age : 30
}

k.gender = 'male'; /*object or json k got extended with new property gender*/

grâce à ross harmes, dustin diaz


-1

Cela permettra d'étendre vos propriétés à créer un nouvel objet avec les prototypes de paramètre d'objet sans modifier l'objet passé.

function extend(object) {
    if (object === null)
        throw TypeError;
    if (typeof object !== "object" && typeof object !== "function")
        throw TypeError;
    if (Object.create)
        return Object.create(object);
    function f() {}
    ;
    f.prototype = p;
    return new f();
}

Mais si vous souhaitez étendre votre Object sans modifier ses paramètres, vous pouvez ajouter extendProperty à votre objet.

var Person{
//some code
extend: extendProperty
}

//Enforce type checking an Error report as you wish
    function extendProperty(object) {
        if ((object !== null && (typeof object === "object" || typeof object === "function"))){
            for (var prop in object) {
                if (object.hasOwnProperty(prop))
                    this[prop] = object[prop];
            }
        }else{
            throw TypeError; //Not an object
        }
    }

-2

Le prototypage est un bon moyen, mais le prototype est parfois assez dangereux et peut conduire à des bugs. Je préfère encapsuler ceci dans un objet de base, comme Ember.js le fait pour Ember.Object.extend et Ember.Object.reopen. C'est beaucoup plus sûr à utiliser.

J'ai créé un aperçu de la façon dont vous configureriez quelque chose de similaire à ce qu'utilise Ember.Object.

Voici le lien: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd


9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.Que veux-tu dire par là? L'utilisation de la chaîne de prototypes en JavaScript peut entraîner des bogues? C'est comme dire que l'utilisation de classes sur Java peut conduire à des bogues et n'a absolument aucun sens.
HMR

@HMR, il dit que l'extension des prototypes d'objets fournis par l'environnement entraîne un code fragile qui pourrait entrer en conflit avec une future fonctionnalité de base du langage JavaScript. Si vous ajoutez une fonction utilitaire utile à tout en étendant Objectle prototype de, votre fonction pourrait avoir le même nom qu'une future fonction JavaScript et provoquer l'explosion de votre code lors de son exécution future. Par exemple, disons que vous avez ajouté une repeat()fonction Objectet l' avez appelée sur des Stringinstances, puis votre environnement d'exécution JavaScript mis à jour vers ES6?
binki

@binki Merci pour votre contribution. Vous parlez de changer le prototype des classes que vous ne «possédez» pas et de briser ainsi la référence d'incapsulation: developer.mozilla.org/en/docs/Web/JavaScript/… JS n'a pas de variables privées donc votre API expose les membres de l'implémentation , qui est généralement résolu par convention (nom du membre de départ avec soulignement). Je ne sais pas si c'est le problème principal de l'op ou si la syntaxe est déroutante et que beaucoup de gens ne la comprennent pas.
HMR du

@HMR, je me trompe peut-être, mais je pense que «mais le prototype est assez dangereux» fait référence au fameux prototype de framework qui pourrait abuser de la prototypefonctionnalité du langage .
binki

Le prototypage est dangereux car si vous utilisez des objets que vous n'avez pas créés, vous ne savez pas toujours quels seront les effets secondaires de leur utilisation comme prototypes. Regardez ce violon par exemple: jsfiddle.net/fo6r20rg
Arkain
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.