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