Ricerca…


Prototipo di funzione standard

Inizia definendo una funzione Foo che useremo come costruttore.

function Foo (){}

Modificando Foo.prototype , possiamo definire proprietà e metodi che saranno condivisi da tutte le istanze di Foo .

Foo.prototype.bar = function() {
  return 'I am bar';
};

Possiamo quindi creare un'istanza utilizzando la new parola chiave e chiamare il metodo.

var foo = new Foo();

console.log(foo.bar()); // logs `I am bar`

Differenza tra Object.key e Object.prototype.key

A differenza dei linguaggi come Python, le proprietà statiche della funzione di costruzione non sono ereditate dalle istanze. Le istanze ereditano solo dal loro prototipo, che eredita dal prototipo del tipo genitore. Le proprietà statiche non vengono mai ereditate.

function Foo() {};
Foo.style = 'bold';

var foo = new Foo();

console.log(Foo.style); // 'bold'
console.log(foo.style); // undefined

Foo.prototype.style = 'italic';

console.log(Foo.style); // 'bold'
console.log(foo.style); // 'italic'

Nuovo oggetto dal prototipo

In JavaScript, qualsiasi oggetto può essere il prototipo di un altro. Quando un oggetto viene creato come prototipo di un altro, erediterà tutte le proprietà del suo genitore.

var proto = { foo: "foo", bar: () => this.foo };

var obj = Object.create(proto);

console.log(obj.foo);
console.log(obj.bar());

Uscita della console:

> "foo"
> "foo"

NOTA Object.create è disponibile da ECMAScript 5, ma qui è un polyfill se è necessario il supporto per ECMAScript 3

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Fonte: http://javascript.crockford.com/prototypal.html


Object.create ()

Il metodo Object.create () crea un nuovo oggetto con l'oggetto prototipo specificato e le proprietà.

Sintassi: Object.create(proto[, propertiesObject])

Parametri :

  • proto (L'oggetto che dovrebbe essere il prototipo dell'oggetto appena creato.)
  • propertiesObject (Facoltativo. Se specificato e non indefinito, un oggetto le cui proprietà enumerabili (cioè quelle proprietà definite su se stesso e non enumerabili lungo la catena del prototipo) specificano i descrittori di proprietà da aggiungere all'oggetto appena creato, con il corrispondente Nomi di proprietà Queste proprietà corrispondono al secondo argomento di Object.defineProperties ()).

Valore di ritorno

Un nuovo oggetto con l'oggetto prototipo specificato e le proprietà.

eccezioni

Un'eccezione TypeError se il parametro proto non è nullo o un oggetto.

Eredità prototipale

Supponiamo di avere un oggetto semplice chiamato prototype :

var prototype = { foo: 'foo', bar: function () { return this.foo; } };

Ora vogliamo un altro oggetto chiamato obj che erediti dal prototype , il che equivale a dire che il prototype è il prototipo di obj

var obj = Object.create(prototype);

Ora tutte le proprietà e i metodi del prototype saranno disponibili per obj

console.log(obj.foo);
console.log(obj.bar());

Uscita della console

"foo"
"foo"

L'ereditarietà del prototipo viene effettuata attraverso i riferimenti agli oggetti internamente e gli oggetti sono completamente mutabili. Ciò significa che qualsiasi modifica apportata a un prototipo inciderà immediatamente su ogni altro oggetto di cui il prototipo è prototipo.

prototype.foo = "bar";
console.log(obj.foo);

Uscita della console

"bar"

Object.prototype è il prototipo di ogni oggetto, quindi è fortemente raccomandato di non rovinarlo, specialmente se usi una libreria di terze parti, ma possiamo giocarci un po '.

Object.prototype.breakingLibraries = 'foo';
console.log(obj.breakingLibraries);
console.log(prototype.breakingLibraries);

Uscita della console

"foo"
"foo"

Fatto divertente Ho usato la console del browser per creare questi esempi e ho infranto questa pagina aggiungendo la proprietà breakingLibraries .


Eredità pseudo-classica

È un'emulazione dell'ereditarietà classica che utilizza l' ereditarietà prototipica che mostra quanto siano potenti i prototipi. È stato creato per rendere la lingua più attraente per i programmatori provenienti da altre lingue.

6

NOTA IMPORTANTE : poiché ES6 non ha senso utilizzare l'ereditarietà pseudo-calssica poiché il linguaggio simula le classi convenzionali . Se non stai usando ES6, dovresti . Se si desidera ancora utilizzare il modello di ereditarietà classico e si è in un ambiente ECMAScript 5 o inferiore, la pseudo-classica è la soluzione migliore.

Una "classe" è solo una funzione che è stata creata per essere chiamata con il new operando ed è utilizzata come costruttore.

function Foo(id, name) {
    this.id = id;
    this.name = name;
}

var foo = new Foo(1, 'foo');
console.log(foo.id);

Uscita della console

1

foo è un'istanza di Foo. La convenzione di codifica JavaScript dice che se una funzione inizia con una maiuscola, può essere chiamata come costruttore (con il new operando).


Per aggiungere proprietà o metodi alla "classe" devi aggiungerli al suo prototipo, che può essere trovato nella proprietà prototype del costruttore.

Foo.prototype.bar = 'bar';
console.log(foo.bar);

Uscita della console

bar

In effetti ciò che Foo sta facendo come "costruttore" è solo la creazione di oggetti con Foo.prototype come prototipo.


Puoi trovare un riferimento al suo costruttore su ogni oggetto

console.log(foo.constructor);

funzione Foo (id, nome) {...

console.log({ }.constructor);

function Object () {[codice nativo]}

E controlla anche se un oggetto è un'istanza di una data classe con l'operatore instanceof

console.log(foo instanceof Foo);

vero

console.log(foo instaceof Object);

vero

Impostazione del prototipo di un oggetto

5

Con ES5 +, la funzione Object.create può essere utilizzata per creare un oggetto con qualsiasi altro oggetto come prototipo.

const anyObj = {
    hello() {
        console.log(`this.foo is ${this.foo}`);
    },
};

let objWithProto = Object.create(anyObj);
objWithProto.foo = 'bar';

objWithProto.hello(); // "this.foo is bar"

Per creare in modo esplicito un oggetto senza un prototipo, utilizzare null come prototipo. Ciò significa che l'oggetto non erediterà Object.prototype da Object.prototype ed è utile per gli oggetti utilizzati per i dizionari di controllo dell'esistenza, ad es

let objInheritingObject = {};
let objInheritingNull = Object.create(null);

'toString' in objInheritingObject; // true
'toString' in objInheritingNull ; // false
6

Da ES6, il prototipo di un oggetto esistente può essere modificato utilizzando, ad esempio, Object.setPrototypeOf

let obj = Object.create({foo: 'foo'});
obj = Object.setPrototypeOf(obj, {bar: 'bar'});

obj.foo; // undefined
obj.bar; // "bar"

Questo può essere fatto quasi ovunque, anche su this oggetto o in un costruttore.

Nota: questo processo è molto lento nei browser correnti e dovrebbe essere usato con parsimonia, provare invece a creare l'oggetto con il prototipo desiderato.

5

Prima di ES5, l'unico modo per creare un oggetto con un prototipo definito manualmente era di costruirlo con un new , per esempio

var proto = {fizz: 'buzz'};

function ConstructMyObj() {}
ConstructMyObj.prototype = proto;

var objWithProto = new ConstructMyObj();
objWithProto.fizz; // "buzz"

Questo comportamento è abbastanza vicino a Object.create che è possibile scrivere un polyfill.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow