web-dev-qa-db-fra.com

Extension d'un objet en Javascript

Je suis 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 extend on object. 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'

Est-ce que quelqu'un sait comment faire ce travail? J'ai entendu dire que vous devez écrire 

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

Mais je ne sais pas comment faire fonctionner ce système. Si ce n'est pas possible, montrez-moi s'il vous plaît une autre alternative qui étend un objet.

137
Wituz

Modifier :
Avant d’utiliser le code, veuillez vérifier les commentaires de user2491400 qui signalent les effets secondaires de l’attribution simple à prototype.

Réponse originale:

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.name = name;
  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
186
osahyoun

Monde sans le "nouveau" mot clé.

Et une syntaxe plus simple avec Object.create ().

Je suis dans le camp qui pense que Javascript devrait essayer de vivre sans "nouveau". C'est un langage sans classes, il n'a pas besoin de constructeurs. Vous créez simplement des objets, puis vous les développez ou les transformez. Certes, il y a des pièges, mais c'est tellement plus puissant et simple:

// base `Person` prototype
const Person = {
   name : '',
   age  : 22,
   type : 'human',
   greet() {
       console.log('Hi, my name is ' + this.name + ' and I am a ' + this.type + '.' )
   }
}

// create an instance of `Person`:
const skywalker = Object.create(Person)
skywalker.name = 'Anakin Skywalker'
skywalker.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Extension 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

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

Un niveau de plus profond

// create a new instance `Robot`
const Astromech = Object.create(Robot)
Astromech.variant = 'astromech'

const r2d2 = Object.create(Astromech)
r2d2.name = 'R2D2'
r2d2.greet() // '0000111010101011100111....'

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

Lectures complémentaires

** Update 3 Oct 18. Adoptez la syntaxe ES6 et utilisez const et let. Exemple ajouté pour montrer comment rendre des propriétés immuables.

** Mise à jour 22 janvier 17. Inclus ES6 Object.assign ().

Comme vous pouvez le constater, l’affectation nécessite plusieurs déclarations. Avec ES6, vous pouvez utiliser la méthode #assign pour raccourcir les affectations. (Pour utiliser polyfill sur des navigateurs plus anciens, voir MDN sur ES6 .)

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

//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
    name: "Robot",
    madeOf: "metal",
    powerConsumption_kWh: 5,
    fullCharge_kWh: 10,
    currentCharge_kWh: 5
})

//attach some methods unique to Robot prototype.
Robot.charge = function(kWh) {
    let self = this
    this.currentCharge_kWh = Math.min(self.fullCharge_kWh, self.currentCharge_kWh + kWh)
    var percentageCharged = this.currentCharge_kWh / this.fullCharge_kWh * 100
    console.log(this.name + (percentageCharged === 100) ? ' is fully charged.' : ' is ' + percentageCharged +'% charged.')
}

Robot.charge(5) // outputs "Robot is fully charged."

Vous pouvez également utiliser le second argument a.k.a propertiesObject de Object.create (), que je trouve un peu trop long. La seule raison de l’utiliser au cours de #assign est si vous avez besoin de plus de contrôle sur les valeurs, c’est-à-dire l’inscriptibilité/la configurabilité, etc. Remarquez que Robot est strictement constitué de métal.

const Robot = Object.create(Person, {
    madeOf: { 
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    powerConsumption: {
        value: "5kWh",
        writable: true,
        configurable: true,
        enumerable: true   
    }
})

Et tous les prototypes de Robot ne peuvent pas être faits d’autre chose.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

Il y a des pièges dans cette configuration qui risquent de faire trébucher les programmeurs "formés de manière classique". Néanmoins, je trouve ce modèle tellement plus lisible.

78
Calvintwr

Si vous n'avez pas encore trouvé de solution, utilisez la propriété associative des objets JavaScript pour ajouter une fonction d'extension au Object.prototype, comme 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);
51
tomilay

Approche différente: Object.create

Selon la réponse de @osahyoun, les éléments suivants constituent un moyen plus 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éer 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

Vérifiez également le MDN documentation.

27
Lior Elrom

Et un an plus tard, je peux vous dire qu’il ya une autre bonne réponse.

Si vous n'aimez pas la manière dont le prototypage fonctionne pour s'étendre sur des objets/classes, tenez-vous-en à ceci: https://github.com/haroldiedema/joii

Exemple de code de possibilités (et beaucoup 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"
18
Harold

Vous voudrez peut-être envisager d'utiliser une bibliothèque auxiliaire telle que underscore.js , qui a sa propre implémentation de extend() .

Et c'est aussi un bon moyen d'apprendre en regardant son code source. La page de code source annotée est très utile.

8
250R

L'objet 'annonce' de Mozilla s'étendant à partir de 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) - 03/2015 versions nocturnes.

6
Niek Vandael

Les personnes qui luttent encore pour une approche simple et optimale, vous pouvez utiliserSpread Syntaxpour étendre un 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 éloignée à droite aura la priorité. Dans cet exemple, person2 est à droite, donc newObj contiendra le nom Robo .

5
Ali Shahbaz

Dans la majorité des projets, il existe des implémentations d’objets étendus: underscore, 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/ Référence/Global_Objects/Object/assign

3
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:

Ignorer ma réponse de 2015 s'il vous plaît. Javascript est maintenant supporté par le mot clé extends 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
2
Abdennour TOUMI

S'IL VOUS PLAÎT AJOUTER RAISON POUR 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 s'ils sont automatiquement encapsulés avec des objets Lorsque cela est nécessaire). 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);

Modifier une instance/un objet spécifique .

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

Modifier la classe

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

Ou simplement dire: é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

0
vijay

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;
};

update: J'ai vérifié this[i] != null car null est un objet

Alors utilisez-le comme:

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

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

defaults.extend(options);

Cela a pour résultat:

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

Résumé:

Javascript utilise un mécanisme appelé héritage prototypal . L'héritage prototype 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.foo ou myObj['foo']), le moteur JS recherchera d'abord cette propriété sur l'objet lui-même.
  2. Lorsque cette propriété ne se trouve pas sur l'objet lui-même, il monte dans la chaîne du prototype / regarde l'objet prototype. Si cette propriété n’est pas trouvée ici, elle continuera à gravir la chaîne de prototypes 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 vais décrire 2 méthodes couramment utilisées.

Exemples:

1. Object.create()

Object.create() est une fonction qui prend un objet en 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 add pour sa propriété d'objet prototype. Les objets créés forment une fonction constructeur lorsque vous utilisez le mot clé new. Leur prototype est défini sur le prototype de la fonction 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