Erweitern eines Objekts in Javascript

164

Ich wandle mich gerade von Java zu Javascript um, und es fällt mir ein bisschen schwer, herauszufinden, wie ich Objekte so erweitern kann, wie ich es möchte.

Ich habe mehrere Leute im Internet gesehen, die eine Methode namens "Erweitern auf Objekt" verwenden. Der Code sieht folgendermaßen aus:

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

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

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

Weiß jemand, wie man diese Arbeit macht? Ich habe gehört, dass Sie schreiben müssen

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

Aber ich weiß nicht, wie ich dieses System zum Laufen bringen soll. Wenn dies nicht möglich ist, zeigen Sie mir bitte eine andere Alternative, die ein Objekt erweitert.

Wituz
quelle
return true; aber deshalb
frage
2
Ich würde vorschlagen, dieses schöne Tutorial auf MDN durchzugehen: - developer.mozilla.org/en/…
Pranav
Wenn Sie nach dem Lesen dieser netten Dokumente immer noch neugierig auf eine extendFunktion sind, habe ich hier ein Beispiel erstellt: jsfiddle.net/k9LRd
Codrin Eugeniu
2
Ich würde auch vorschlagen, es nicht streng als "Transformation von Java zu JavaScript" und mehr als "Erlernen einer neuen Sprache, Javascript, die eine ähnliche Syntax wie Java hat" zu betrachten
Toni Leigh

Antworten:

195

Sie möchten vom Prototypobjekt der Person "erben":

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
osahyoun
quelle
4
Ich habe eine Frage: Wie wird der Person()Konstruktor aufgerufen, wenn Sie dies tun new Robot()? Es scheint mir, dass Sie diesen Basisklassenkonstruktor aufrufen sollten, anstatt ihn this.name = name;im Robot()Konstruktor zu tun ...
Alexis Wilke
21
@AlexisWilke: Ja, du solltest anrufen Person.apply(this, arguments);. Es wäre auch besser, Robot.prototype = Object.create(Person.prototype);statt zu verwenden new Person();.
Felix Kling
18
Wie von Felix angegeben, 'Robot.prototype = Person.prototype;' ist eine schlechte Idee, wenn jemand möchte, dass der Typ 'Robot' eine eigene Prototypinstanz hat. Das Hinzufügen neuer roboterspezifischer Funktionen würde es auch der Person hinzufügen.
James Wilkins
20
Dieses Beispiel ist völlig falsch. Auf diese Weise ändern Sie den Prototyp der Person. Das ist keine Vererbung und Sie riskieren ein großes Durcheinander in der Personenklasse. Siehe die Antwort, die die Verwendung von Object.create () empfiehlt. Das ist der richtige Weg, um Dinge zu tun.
Nicolas-van
6
@osahyoun Diese Antwort hat einen hohen Stellenwert in der Google-Suche. Ich würde wirklich vorschlagen, dass Sie den Code korrigieren und die Prototypenkette korrigieren, wie in anderen Kommentaren hier vorgeschlagen.
Raphaëλ
101

Welt ohne das "neue" Schlüsselwort.

Und einfachere "prosaähnliche" Syntax mit Object.create ().

* Dieses Beispiel wurde für ES6-Klassen aktualisiert.

Denken Sie zunächst daran, dass Javascript eine prototypische Sprache ist . Es ist nicht klassenbasiert. Daher enthüllt das Schreiben in prototypischer Form seine wahre Natur und kann sehr einfach, prosaartig und kraftvoll sein.

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'

Nein, Sie brauchen keine Konstruktoren, keine newInstanziierung ( lesen Sie, warum Sie sie nicht verwenden solltennew ), nein super, kein lustiger Witz __construct. Sie erstellen einfach Objekte und erweitern oder verwandeln sie dann.

( Wenn Sie sich mit Gettern und Setzern auskennen, lesen Sie den Abschnitt "Weiterführende Literatur", um zu erfahren, wie Sie mit diesem Muster kostenlose Getter und Setter erhalten, wie Javascript es ursprünglich beabsichtigt hatte, und wie leistungsfähig sie sind .)

Prosaähnliche Syntax: Basisprototyp

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!

Sieht auf einen Blick gut lesbar aus.

Erweiterung, die einen Nachkommen von erstellt Person

* Die richtigen Begriffe sind prototypesund ihre descendants. Es gibt keine classesund keine Notwendigkeit für 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

Eine Möglichkeit, eine "Standard" -Methode zum Erstellen eines zu erstellen descendant, besteht darin, eine #createMethode anzuhängen :

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')

Die folgenden Möglichkeiten haben eine geringere Lesbarkeit:

Vergleichen Sie mit dem "klassischen" Äquivalent:

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!

Die Lesbarkeit des Codes im "klassischen" Stil ist nicht so gut.

ES6-Klassen

Zugegeben, einige dieser Probleme werden von den ES6-Klassen beseitigt, aber dennoch:

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

Verzweigung des Basisprototyps

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

Fügen Sie Methoden hinzu, die für 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

Vererbung überprüfen

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

Sie haben schon alles, was Sie brauchen! Keine Konstruktoren, keine Instanziierung. Saubere, klare Prosa.

Weiterführende Literatur

Beschreibbarkeit, Konfigurierbarkeit und kostenlose Getter und Setter!

Für kostenlose Getter und Setter oder zusätzliche Konfigurationen können Sie das zweite Argument von Object.create () verwenden, auch bekannt als propertiesObject. Es ist auch in # Object.defineProperty und # Object.defineProperties verfügbar .

Um zu veranschaulichen, wie mächtig dies ist, möchten wir, dass alle Robotstreng aus Metall (via writable: false) bestehen und powerConsumptionWerte standardisieren (via Getter und Setter).

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

Und alle Prototypen von Robotkönnen nicht madeOfetwas anderes sein, weil writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

Mixins (mit # Object.assign) - Anakin Skywalker

Kannst du spüren, wohin das führt ...?

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

Object.assign(darthVader, Robot)

Darth Vader erhält die Methoden von Robot:

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

Zusammen mit anderen seltsamen Dingen:

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

Nun, ob Darth Vader Mensch oder Maschine ist, ist in der Tat subjektiv:

"Er ist jetzt mehr Maschine als Mensch, verdreht und böse." - Obi Wan Kenobi

"Ich weiß, dass es gut in dir ist." - Luke Skywalker

Extra - Etwas kürzere Syntax mit # Object.assign

Höchstwahrscheinlich verkürzt dieses Muster Ihre Syntax. ES6 # Object.assign kann sich jedoch noch etwas verkürzen (Informationen zur Verwendung von Polyfill in älteren Browsern finden Sie unter MDN in 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.
})
Calvintwr
quelle
7
habe eine positive Bewertung dafür, dass keine Konstruktorfunktion verwendet wird.
nsmarks
1
"klassisch ausgebildete" Programmierer, was meinst du damit?
Petra
1
Ich komme aus einer klassischen OOP-Denkweise und diese Antwort hat mir sehr geholfen. Zwei Fragen zum Code: 1) Ist die heutige ES2015 Object.assign(Robot, {a:1}eine gute Alternative für Ihre extend()Methode? 2) Wie überschreibe ich die greet()Methode, damit sie denselben Text zurückgibt, aber eine "Begrüßungsüberschreibung" angehängt ist?
Barry Staes
2
1) #Object.assignsieht aus wie eine gute Alternative. Die Browserunterstützung ist jedoch geringer. 2) Sie verwenden die __proto__Eigenschaft des Objekts, um auf die Begrüßungsfunktion des Prototyps zuzugreifen. Anschließend rufen Sie die Begrüßungsfunktion des Prototyps mit dem übergebenen Bereich des Angerufenen auf. In diesem Fall war die Funktion ein Konsolenprotokoll, sodass kein "Anhängen" möglich ist. Aber mit diesem Beispiel denke ich, dass Sie die Drift bekommen. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr
1
Nun, das ist eine Diskussion, die mit den Betreuern der ECMAScript-Sprachspezifikation geführt werden sollte. Ich stimme im Allgemeinen zu, aber ich muss mit dem arbeiten, was ich habe.
51

Wenn Sie noch keinen Weg gefunden haben, verwenden Sie die assoziative Eigenschaft von JavaScript-Objekten, um der Object.prototypeunten gezeigten Funktion eine Erweiterungsfunktion hinzuzufügen .

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

Sie können diese Funktion dann wie unten gezeigt verwenden.

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

o.extend(x);
Tomilay
quelle
18
Beachten Sie, dass dadurch Zeiger auf das ursprüngliche Objekt in der untergeordneten Klasse erstellt werden, wenn Objekte / Arrays in der übergeordneten Klasse verwendet werden. Um dies näher zu erläutern: Wenn Sie ein Objekt oder Array in Ihrer übergeordneten Klasse haben und es in einer untergeordneten Klasse ändern, die sich auf dieser Basis erstreckt, wird es tatsächlich für alle untergeordneten Klassen geändert, die sich auf derselben Basisklasse erstrecken.
Harold
Harold, danke, dass du diese Tatsache hervorgehoben hast. Für jeden, der die Funktion verwendet, ist es wichtig, eine Bedingung aufzunehmen, die nach Objekten / Arrays sucht und Kopien davon erstellt.
Tomilay
30

Anderer Ansatz: Object.create

Per @ osahyoun-Antwort finde ich Folgendes als eine bessere und effizientere Möglichkeit, vom Prototypobjekt einer Person zu "erben":

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;

Neue Instanzen erstellen:

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

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

Verwenden Sie jetzt Object.create :

Person.prototype.constructor !== Robot

Überprüfen Sie auch die MDN- Dokumentation.

Lior Elrom
quelle
2
Ich möchte nur sagen, dass @GaretClaborn korrekt funktioniert, aber Sie übergeben den nameParameter nicht wie folgt an den übergeordneten Konstruktor: jsfiddle.net/3brm0a7a/3 (Unterschied ist in Zeile 8)
xPheRe
1
@xPheRe Ah ich verstehe, danke. Ich habe die Antwort bearbeitet, um diese Änderung widerzuspiegeln
Garet Claborn
1
@xPheRe, ich glaube, ich habe mich mehr darauf konzentriert, einen Punkt zu beweisen, als ich diese Lösung hinzugefügt habe. Vielen Dank.
Lior Elrom
1
Schöne Antwort +1, Sie können einen Blick auf ECMAScript 6 werfen. Schlüsselwörter Klasse und Erweiterungen sind verfügbar: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Benjamin Poignant
26

In ES6 können Sie Spread-Operatoren wie verwenden

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

Beachten Sie, dass Object.assign () Setter auslöst, während die Spread-Syntax dies nicht tut.

Weitere Informationen finden Sie unter dem Link MDN-Spread-Syntax


Alte Antwort:

In ES6 gibt es Object.assignzum Kopieren von Eigenschaftswerten. Verwendung {}als erster param , wenn Sie nicht das Zielobjekt (das erste param bestanden) ändern mögen.

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

Weitere Details finden Sie unter Link, MDN - Object.assign ()

Falls Sie eine Polyfill für ES5 benötigen , bietet der Link diese ebenfalls an. :) :)

KrIsHnA
quelle
18

Und ein weiteres Jahr später kann ich Ihnen sagen, dass es eine weitere nette Antwort gibt.

Wenn Ihnen die Funktionsweise des Prototyping zur Erweiterung von Objekten / Klassen nicht gefällt, lesen Sie Folgendes: https://github.com/haroldiedema/joii

Schneller Beispielcode für Möglichkeiten (und viele mehr):

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"
Harold
quelle
Nun, ich habe noch 2 Monate Zeit, bis die 2 Jahre abgelaufen sind: P Wie auch immer, JOII 3.0 steht kurz vor der Veröffentlichung :)
Harold
1
Machen Sie das 3 Jahre später.
Interessantes Konzept, aber die Syntax sieht wirklich hässlich aus. Warten Sie besser darauf, dass die ES6-Klassen stabil werden
schläfrig am
Ich stimme @sleepycal voll und ganz zu. Leider wird es noch mindestens 5 Jahre dauern, bis alle gängigen Browser dies implementiert haben. Also bis zu diesem Zeitpunkt muss dies tun ...
Harold
12

Menschen, die immer noch um den einfachen und besten Ansatz kämpfen, können Sie Spread Syntaxzum Erweitern von Objekten verwenden.

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

Hinweis: Denken Sie daran, dass die am weitesten rechts liegende Eigenschaft Vorrang hat. In diesem Beispiel person2befindet sich auf der rechten Seite der newObjName Robo .

Ali Shahbaz
quelle
6

Mozilla "kündigt" Objekt an, das sich von ECMAScript 6.0 erstreckt:

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

HINWEIS: Dies ist eine experimentelle Technologie, die Teil des ECMAScript 6 (Harmony) -Vorschlags ist.

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

Diese Technologie ist in Gecko (Google Chrome / Firefox) verfügbar - 03/2015 Nightly Builds.

Niek Vandael
quelle
4

In den meisten Projekten gibt es eine Implementierung der Objekterweiterung: Unterstrich, Abfrage, Lodash: Erweitern .

Es gibt auch eine reine Javascript-Implementierung, die Teil von ECMAscript 6 ist: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Cezary Daniel Nowak
quelle
Bezieht sich „reine Javascript-Implementierung“ nicht auf etwas, das nur mit JavaScript implementiert wird, nicht auf eine von der Umgebung bereitgestellte Funktion, die möglicherweise nativ implementiert wird?
Binki
1
@binki, ich meinte native Javascript-Implementierung - Teil des ECMAScript 2015 (ES6) -Standards
Cezary Daniel Nowak
2
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Dann:

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

Update 01/2017:

Bitte ignorieren Sie meine Antwort von 2015, da Javascript jetzt das extendsSchlüsselwort seit ES6 unterstützt (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
Abdennour TOUMI
quelle
1
Durch Aufrufen new ParentClass()vor dem Überschreiben des Konstruktors haben Sie den übergeordneten Konstruktor bereits ausgeführt. Ich denke nicht, dass das korrektes Verhalten ist, wenn Sie mich fragen ...
Harold
1

Zusammenfassung:

Javascript verwendet einen Mechanismus, der als prototypische Vererbung bezeichnet wird . Die prototypische Vererbung wird verwendet, wenn eine Eigenschaft für ein Objekt gesucht wird. Wenn wir Eigenschaften in Javascript erweitern, erben wir diese Eigenschaften von einem tatsächlichen Objekt. Es funktioniert folgendermaßen:

  1. Wenn eine Objekteigenschaft angefordert wird (z myObj.foo oder myObj['foo']), sucht die JS-Engine zuerst nach dieser Eigenschaft im Objekt selbst
  2. Wenn diese Eigenschaft nicht für das Objekt selbst gefunden wird, wird die Prototypenkette auf das Prototypobjekt angehoben. Wenn diese Eigenschaft auch hier nicht gefunden wird, klettert sie die Prototypenkette weiter, bis die Eigenschaft gefunden wird. Wenn die Eigenschaft nicht gefunden wird, wird ein Referenzfehler ausgegeben.

Wenn wir von einem Objekt in Javascript aus erweitern möchten, können wir dieses Objekt einfach in der Prototypenkette verknüpfen. Es gibt zahlreiche Möglichkeiten, dies zu erreichen. Ich werde zwei häufig verwendete Methoden beschreiben.

Beispiele:

1. Object.create()

Object.create()ist eine Funktion, die ein Objekt als Argument verwendet und ein neues Objekt erstellt. Das Objekt, das als Argument übergeben wurde, ist der Prototyp des neu erstellten Objekts. Beispielsweise:

// 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. Explizites Festlegen der Prototyp-Eigenschaft

Beim Erstellen von Objekten mit Konstruktorfunktionen können wir festlegen, dass der Prototyp-Objekteigenschaft Eigenschaften hinzugefügt werden. Bei Objekten, die bei Verwendung des newSchlüsselworts eine Konstruktorfunktion bilden , wird der Prototyp auf den Prototyp der Konstruktorfunktion gesetzt. Beispielsweise:

// 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));

Willem van der Veen
quelle
0

Sie können es einfach tun, indem Sie:

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: Ich habe für this[i] != nullda nullist ein Objekt

Dann benutze es wie folgt:

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

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

defaults.extend(options);

Dies führt zu:

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

BITTE GRUND FÜR DOWNVOTE HINZUFÜGEN

  • Zum Erweitern muss keine externe Bibliothek verwendet werden

  • In JavaScript ist alles ein Objekt (mit Ausnahme der drei primitiven Datentypen, und selbst sie werden bei Bedarf automatisch mit Objekten umbrochen). Darüber hinaus sind alle Objekte veränderlich.

Klassenperson in 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);

Ändern Sie eine bestimmte Instanz / ein bestimmtes Objekt .

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

Ändern Sie die Klasse

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

Oder sagen Sie einfach: Erweitern Sie JSON und OBJECT. Beide sind gleich

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

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

Dank Ross Schaden, Dustin Diaz

Vijay
quelle
-1

Dadurch können Sie Ihre Eigenschaften erweitern und ein neues Objekt mit den Objektparameter-Prototypen erstellen, ohne das übergebene Objekt zu ändern.

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

Wenn Sie Ihr Objekt jedoch erweitern möchten, ohne die Parameter zu ändern, können Sie Ihrem Objekt expandProperty hinzufügen.

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
        }
    }
Ndifreke
quelle
-2

Prototyping ist ein guter Weg, aber Prototypen sind manchmal ziemlich gefährlich und können zu Fehlern führen. Ich ziehe es vor, dies in ein Basisobjekt zu kapseln, wie es Ember.js mit Ember.Object.extend und Ember.Object.reopen tut. Das ist viel sicherer zu bedienen.

Ich habe eine Übersicht darüber erstellt, wie Sie etwas Ähnliches wie Ember.Object einrichten würden.

Hier ist der Link: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd

Vinicius Dallacqua
quelle
9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.Was meinst du damit? Die Verwendung der Prototypenkette in JavaScript kann zu Fehlern führen. Es ist wie zu sagen, dass die Verwendung von Klassen unter Java zu Fehlern führen kann und absolut keinen Sinn ergibt.
HMR
@HMR Er sagt, dass das Erweitern von Objektprototypen, die von der Umgebung bereitgestellt werden, zu fragilem Code führt, der möglicherweise mit einer zukünftigen JavaScript-Kernsprachenfunktion in Konflikt steht. Wenn Sie durch Erweitern Objectdes Prototyps zu allem eine nützliche Dienstprogrammfunktion hinzufügen , hat Ihre Funktion möglicherweise denselben Namen wie eine zukünftige JavaScript-Funktion und führt dazu, dass Ihr Code explodiert, wenn er in Zukunft ausgeführt wird. Angenommen, Sie haben eine repeat()Funktion zu Instanzen hinzugefügt Objectund diese für StringInstanzen aufgerufen und anschließend Ihre JavaScript-Laufzeit auf ES6 aktualisiert.
Binki
@binki Vielen Dank für Ihre Eingabe. Sie sprechen über das Ändern des Prototyps von Klassen, die Sie nicht "besitzen", und damit das Aufbrechen der Inkapselungsreferenz: developer.mozilla.org/en/docs/Web/JavaScript/… JS verfügt nicht über private Variablen, sodass Ihre API Implementierungsmitglieder verfügbar macht , das wird normalerweise durch Konvention gelöst (Name des Mitglieds mit Unterstrich beginnen). Ich bin mir nicht sicher, ob dies das Hauptproblem der Operation ist oder ob die Syntax verwirrend ist und viele Leute es nicht verstehen.
HMR
@HMR, ich kann mich irren, aber ich denke , „aber Prototyp ist ziemlich gefährlich“ bezieht sich auf den berüchtigten Prototyp Rahmen , die den Missbrauch könnte prototypeSprache - Funktion .
Binki
Prototyping ist gefährlich, da Sie bei Verwendung von Objekten, die Sie nicht erstellt haben, nicht immer wissen, welche Nebenwirkungen die Verwendung als Prototypen haben wird. Schauen Sie sich diese Geige zum Beispiel an: jsfiddle.net/fo6r20rg
Arkain