Estensione di un oggetto in Javascript


164

Attualmente sto passando da Java a Javascript, ed è un po 'difficile per me capire come estendere gli oggetti nel modo in cui voglio.

Ho visto diverse persone su Internet utilizzare un metodo chiamato extendere sull'oggetto. Il codice sarà simile al seguente:

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

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

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

Qualcuno sa come farlo funzionare? Ho sentito che devi scrivere

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

Ma non so come far funzionare questo sistema. Se non è possibile, mostrami un'altra alternativa che estende un oggetto.


ritorno vero; ma è per questo che chiedo :)
Wituz,

2
suggerirei di passare attraverso questo bellissimo tutorial su MDN: - developer.mozilla.org/it/…
Pranav,

Se dopo aver letto quei bei documenti sei ancora curioso di una extendfunzione, ho creato un esempio qui: jsfiddle.net/k9LRd
Codrin Eugeniu,

2
suggerirei anche di non pensarci rigorosamente come "trasformazione da Java a JavaScript" e più come "apprendimento di una nuova lingua, Javascript, che ha una sintassi simile a Java"
Toni Leigh,

Risposte:


195

Vuoi "ereditare" dall'oggetto prototipo di 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
Ho una domanda: come viene Person()chiamato il costruttore quando lo fai new Robot()? Mi sembra che dovresti chiamare quel costruttore di classe base invece di farlo this.name = name;nel Robot()costruttore ...
Alexis Wilke,

21
@AlexisWilke: Sì, dovresti chiamare Person.apply(this, arguments);. Sarebbe anche meglio usare Robot.prototype = Object.create(Person.prototype);invece di new Person();.
Felix Kling,

18
Come affermato da Felix, "Robot.prototype = Person.prototype;" è una cattiva idea se qualcuno desidera che il tipo 'Robot' abbia la propria istanza prototipo. L'aggiunta di nuove funzioni specifiche del robot lo aggiungerebbe anche alla persona.
James Wilkins,

20
Questo esempio è completamente sbagliato. In questo modo si modifica il prototipo di Person. Questa non è eredità e rischi di mettere un casino enorme nella classe Person. Vedi la risposta che consiglia di utilizzare Object.create (). Questo è il modo corretto di fare le cose.
nicolas-van,

6
@osahyoun questa risposta ha un alto posizionamento nella ricerca di Google. Vorrei davvero suggerire di correggere il codice e correggere la catena di prototipi come suggerito da altri commenti qui.
raphaëλ,

103

Mondo senza la "nuova" parola chiave.

E più semplice sintassi "simile a una prosa" con Object.create ().

* Questo esempio è aggiornato per le classi ES6.

Prima di tutto, ricorda che Javascript è un linguaggio prototipo . Non è basato sulla classe. Quindi, la scrittura in forma prototipica espone la sua vera natura e può essere molto semplice, simile alla prosa e potente.

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'

No, non hai bisogno di costruttori, nessuna newistanza ( leggi perché non dovresti usarenew ), no super, niente di divertente __construct. È sufficiente creare oggetti e quindi estenderli o trasformarli.

( Se conosci getter e setter, vedi la sezione "Ulteriori letture" per vedere come questo modello ti offre getter e setter gratuiti in un modo che Javascript aveva originariamente previsto e quanto sono potenti .)

Sintassi simile alla prosa: protoipo di 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!

A prima vista, sembra molto leggibile.

Estensione, creando un discendente di Person

* I termini corretti sono prototypese loro descendants. Non ce ne sono classese non è necessario 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

Un modo per fornire un modo "predefinito" di creare un descendantè collegando un #createmetodo:

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

I modi seguenti hanno una leggibilità inferiore:

Confronta con l'equivalente "classico":

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 leggibilità del codice usando lo stile "classico" non è così buona.

Classi ES6

Certo, alcuni di questi problemi vengono sradicati dalle classi ES6, ma comunque:

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

Diramazione del prototipo di 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

Associare metodi univoci a 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

Verifica dell'eredità

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

Hai già tutto ciò di cui hai bisogno! Nessun costruttore, nessuna istanza. Prosa pulita e chiara.

Ulteriori letture

Scrittibilità, configurabilità e setter e setter gratuiti!

Per getter e setter gratuiti, o configurazione aggiuntiva, puoi usare il secondo argomento di Object.create (), noto anche come propertiesObject. È disponibile anche in # Object.defineProperty e # Object.defineProperties .

Per illustrare quanto sia potente, supponiamo di voler Robotrigorosamente tutto in metallo (via writable: false) e standardizzare i powerConsumptionvalori (tramite getter e 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

E tutti i prototipi di Robotnon possono essere madeOfqualcos'altro perché writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

Mixins (usando # Object.assign) - Anakin Skywalker

Puoi percepire dove sta andando ...?

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

Object.assign(darthVader, Robot)

Darth Vader ottiene i metodi di Robot:

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

Insieme ad altre cose strane:

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

Bene, se Darth Vader sia uomo o macchina è davvero soggettivo:

"Adesso è più una macchina che un uomo, contorto e malvagio." - Obi-Wan Kenobi

"So che c'è del buono in te." - Luke Skywalker

Extra: sintassi leggermente più breve con # Object.assign

Con ogni probabilità, questo modello accorcia la sintassi. Ma ES6 # Object.assign può accorciare ulteriormente (per polyfill da utilizzare su browser meno recenti, vedere MDN su 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
avere un voto per non usare una funzione di costruzione.
nsmarks

1
programmatori "di formazione classica", cosa intendi con questo?
Petra,

1
Vengo dalla classica mentalità OOP e questa risposta mi ha aiutato molto. Due domande sul codice: 1) ES2015 di oggi è Object.assign(Robot, {a:1}una buona alternativa al tuo extend()metodo? 2) Come sovrascrivere il greet()metodo in modo che restituisca lo stesso testo, ma con "un saluto di sostituzione" aggiunto?
Barry Staes,

2
1) #Object.assignsembra una buona alternativa. Ma il supporto del browser è di livello inferiore. 2) Utilizzerai la __proto__proprietà dell'oggetto per accedere alla funzione di saluto del suo prototipo. quindi si chiama la funzione di saluto del prototipo con l'ambito della chiamata inoltrato. in questo caso la funzione era un registro della console, quindi non è possibile "aggiungere". Ma con questo esempio penso che tu abbia la deriva. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr

1
Bene, questa è una discussione che dovrebbe essere tenuta con i manutentori delle specifiche del linguaggio ECMAScript. Sono generalmente d'accordo, ma devo lavorare con quello che ho.

51

Se non hai ancora trovato un modo, usa la proprietà associativa degli oggetti JavaScript per aggiungere una funzione di estensione a Object.prototypecome mostrato di seguito.

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

È quindi possibile utilizzare questa funzione come mostrato di seguito.

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

o.extend(x);

18
Fare attenzione che ciò creerà puntatori all'oggetto originale nella classe 'figlio' quando si usano oggetti / matrici nella classe 'genitore'. Per elaborare: Se si dispone di un oggetto o di un array nella classe genitore, modificandolo in una classe figlio che si estende su quella base, lo modificherà effettivamente per tutte le classi figlio che si estendono su questa stessa classe base.
Harold,

Harold, grazie per aver messo in evidenza questo fatto. È importante per chiunque utilizzi la funzione di incorporare una condizione che verifica la presenza di oggetti / matrici e ne fa copie.
domani

30

Approccio diverso: Object.create

Per la risposta di @osahyoun, trovo quanto segue come un modo migliore ed efficiente per "ereditare" dall'oggetto prototipo di 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;

Crea nuove istanze:

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

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

Ora, usando Object.create :

Person.prototype.constructor !== Robot

Controlla anche la documentazione MDN .


2
Voglio solo dire che @GaretClaborn funziona correttamente, ma non stai passando il nameparametro al costruttore principale, in questo modo: jsfiddle.net/3brm0a7a/3 (la differenza è nella riga # 8)
xPheRe

1
@xPheRe Ah, grazie. Ho modificato la risposta per riflettere quel cambiamento
Garet Claborn il

1
@xPheRe, immagino di essere stato più concentrato nel dimostrare un punto quando ho aggiunto questa soluzione. Grazie.
Lior Elrom,

1
Bella risposta +1, puoi dare un'occhiata a ECMAScript 6. La classe di parole chiave ed estensioni è disponibile: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Benjamin Poignant,

26

In ES6 , è possibile utilizzare l'operatore spread come

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

Si noti che Object.assign () innesca setter mentre la sintassi spread no.

Per maggiori informazioni vedi link, MDN -Spread Sintassi


Vecchia risposta:

In ES6 , esiste la Object.assigncopia dei valori delle proprietà. Utilizzare {}come primo parametro se non si desidera modificare l'oggetto di destinazione (il primo parametro è passato).

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

Per maggiori dettagli vedi link, MDN - Object.assign ()

Nel caso in cui sia necessario un Polyfill per ES5 , anche il collegamento lo offre. :)


18

E un altro anno dopo, posso dirti che c'è un'altra bella risposta.

Se non ti piace il modo in cui funziona la prototipazione per estendere oggetti / classi, dai un'occhiata a questo: https://github.com/haroldiedema/joii

Esempio rapido di codice di possibilità (e molti altri):

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"

Bene, ho ancora 2 mesi fino al termine dei 2 anni: P In entrambi i casi, JOII 3.0 sta per essere rilasciato :)
Harold,

1
Fallo 3 anni dopo.

Concetto interessante, ma la sintassi sembra davvero brutta. Faresti meglio ad aspettare che le lezioni ES6 diventino stabili
sleepycal il

Sono completamente d'accordo @sleepycal. Sfortunatamente, ci vorranno almeno altri 5 anni prima che tutti i browser principali / comuni lo abbiano implementato. Quindi fino a quel momento, questo dovrà fare ...
Harold,

12

Le persone che stanno ancora lottando per l'approccio semplice e migliore, è possibile utilizzare Spread Syntaxper estendere l'oggetto.

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

Nota: Ricorda che la proprietà più lontana a destra avrà la priorità. In questo esempio, person2è sul lato destro, quindi newObjavrà il nome Robo in esso.



6

Mozilla "annuncia" l'oggetto che si estende da ECMAScript 6.0:

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

NOTA: questa è una tecnologia sperimentale, parte della proposta 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;     } 
}

Questa tecnologia è disponibile in Gecko (Google Chrome / Firefox) - build notturne del 03/2015.


4

Nella maggior parte dei progetto ci sono alcuni attuazione dell'oggetto estende: sottolineatura, jquery, lodash: estendere .

Esiste anche un'implementazione javascript pura, che fa parte di ECMAscript 6: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


La "pura implementazione javascript" non si riferisce a qualcosa che è implementato solo con JavaScript, non a una funzione fornita dall'ambiente che potrebbe essere implementata in modo nativo?
binki,

1
@binki, intendevo l'implementazione nativa di JavaScript - parte dello standard ECMAScript 2015 (ES6)
Cezary Daniel Nowak,

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

Poi:

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

Aggiornamento 01/2017:

Per favore, ignora la mia risposta del 2015 poiché Javascript è ora supportato extends parola chiave da 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
Chiamando new ParentClass()prima di sovrascrivere il costruttore, hai già eseguito il costruttore principale. Non penso che sia il comportamento corretto se me lo chiedi ...
Harold,

1

Sommario:

Javascript utilizza un meccanismo chiamato ereditarietà prototipale . L'ereditarietà prototipale viene utilizzata quando si cerca una proprietà su un oggetto. Quando estendiamo le proprietà in JavaScript, ereditiamo queste proprietà da un oggetto reale. Funziona nel modo seguente:

  1. Quando viene richiesta una proprietà dell'oggetto, (ad esempio myObj.fooo myObj['foo']) il motore JS cercherà prima quella proprietà sull'oggetto stesso
  2. Quando questa proprietà non viene trovata sull'oggetto stesso, salirà la catena prototipo guardando l'oggetto prototipo. Se questa proprietà non viene trovata qui, continuerà a salire la catena del prototipo fino a quando non viene trovata la proprietà. Se la proprietà non viene trovata, verrà generato un errore di riferimento.

Quando vogliamo estendere da un oggetto in JavaScript possiamo semplicemente collegare questo oggetto nella catena di prototipi. Ci sono molti modi per raggiungere questo obiettivo, descriverò 2 metodi comunemente usati.

Esempi:

1. Object.create()

Object.create()è una funzione che accetta un oggetto come argomento e crea un nuovo oggetto. L'oggetto che è stato passato come argomento sarà il prototipo dell'oggetto appena creato. Per esempio:

// 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. Impostazione esplicita della proprietà del prototipo

Quando si creano oggetti utilizzando le funzioni di costruzione, è possibile impostare aggiungere proprietà alla proprietà dell'oggetto prototipo. Gli oggetti creati formano una funzione di costruzione quando si utilizza la newparola chiave, il loro prototipo è impostato sul prototipo della funzione di costruzione. Per esempio:

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

Puoi semplicemente farlo usando:

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

aggiornamento: ho controllato this[i] != nullpoiché nullè un oggetto

Quindi usalo come:

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

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

defaults.extend(options);

Ciò si traduce in:

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

0

PER FAVORE AGGIUNGI MOTIVO PER DOWNVOTE

  • Non è necessario utilizzare alcuna libreria esterna per estenderla

  • In JavaScript, tutto è un oggetto (ad eccezione dei tre tipi di dati primitivi e persino vengono automaticamente avvolti con oggetti quando necessario). Inoltre, tutti gli oggetti sono mutabili.

Persona di classe 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);

Modifica un'istanza / oggetto specifici .

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

Modifica la classe

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

O semplicemente dire: estendere JSON e OBJECT sono entrambi uguali

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

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

grazie ai danni di ross, dustin diaz


-1

Ciò consentirà di estendere le proprietà creando un nuovo oggetto con i prototipi dei parametri oggetto senza alterare l'oggetto passato.

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

Ma se vuoi estendere il tuo oggetto senza modificarlo, puoi aggiungere extensionProperty al tuo oggetto.

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

Il prototipo è un bel modo, ma il prototipo a volte è abbastanza pericoloso e può portare a bug. Preferisco incapsulare questo in un oggetto base, come fa Ember.js con Ember.Object.extend ed Ember.Object.reopen. È molto più sicuro da usare.

Ho creato un'idea su come impostare qualcosa di simile a quello che utilizza Ember.Object.

Ecco il link: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd


9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.Cosa vuoi dire con questo? L'uso della catena di prototipi in JavaScript può portare a bug? È come dire che l'uso delle classi su Java può portare a bug e non ha assolutamente senso.
HMR,

@HMR sta dicendo che l'estensione dei prototipi di oggetti forniti dall'ambiente provoca un fragile codice che potrebbe entrare in conflitto con una futura funzionalità del linguaggio JavaScript di base. Se aggiungi un'utile funzione di utilità a tutto estendendo Objectil prototipo, la tua funzione potrebbe avere lo stesso nome di una futura funzione JavaScript e far esplodere il tuo codice quando eseguito in futuro. Ad esempio, supponiamo che tu abbia aggiunto una repeat()funzione Objecte l'abbia chiamata su Stringistanze e che il tuo runtime JavaScript sia stato aggiornato a ES6?
binki,

@binki Grazie per il tuo contributo. Stai parlando di cambiare il prototipo di classi che non "possiedi" e quindi di interrompere il riferimento all'incapsulamento: developer.mozilla.org/en/docs/Web/JavaScript/… JS non ha variabili private, quindi la tua API espone i membri dell'implementazione , che di solito viene risolto per convenzione (inizia il nome del membro con trattino basso). Non sono sicuro se questo sia il problema principale dell'op o se la sintassi sia confusa e molte persone non lo capiscono.
HMR,

@HMR, potrei sbagliarmi, ma penso che "ma il prototipo è abbastanza pericoloso" si riferisce al famigerato framework di prototipi che potrebbe abusare della prototypefunzionalità del linguaggio .
binki,

Il prototipo è pericoloso perché se usi oggetti che non hai creato, non sai sempre quali saranno gli effetti collaterali del loro utilizzo come prototipi. Guarda questo violino per esempio: jsfiddle.net/fo6r20rg
Arkain,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.