Nota: È considerata una cattiva prassi modificare il valore di __proto__
. Farlo è fortemente scoraggiato da Brendan Eich, il creatore di JavaScript, tra gli altri. In effetti la proprietà __proto__
è stata completamente rimossa da alcuni motori JavaScript come Rhino. Se vuoi sapere perché allora leggi lo following comment di Brendan Eich.
Aggiornamento: I browser non rimuovono la proprietà __proto__
. Infatti, ECMAScript Harmony ha ora standardizzato sia la proprietà __proto__
sia la funzione setPrototypeOf
. La proprietà __proto__
è supportata solo per motivi legacy. Si consiglia vivamente di utilizzare setPrototypeOf
e getPrototypeOf
anziché __proto__
.
Attenzione: Anche se setPrototypeOf
è ora uno standard, si sta ancora scoraggiati dal usarlo perché mutando il prototipo di un oggetto uccide invariabilmente ottimizzazioni e rende il codice più lento. Inoltre, l'uso di setPrototypeOf
è solitamente un'indicazione di codice di scarsa qualità.
Non è necessario preoccuparsi che il codice esistente non funzioni un giorno. La proprietà __proto__
è qui per rimanere.
Ora, per la domanda in questione. Vogliamo fare qualcosa di simile a questo in un modo compatibile con gli standard:
var a = {
b: "ok"
};
a.__proto__ = {
a: "test"
};
alert(a.a); // alerts test
alert(a.b); // alerts ok
Ovviamente non è possibile utilizzare Object.create
per raggiungere questo fine dal momento che non si sta creando un nuovo oggetto. Stiamo solo provando a modificare la proprietà interna [[proto]]
dell'oggetto specificato. Il problema è che non è possibile modificare la proprietà interna di [[proto]]
di un oggetto una volta creata (eccetto usando __proto__
che stiamo cercando di evitare).
Quindi, per risolvere questo problema ho scritto una semplice funzione (si noti che funziona per tutti gli oggetti ad eccezione di funzioni):
function setPrototypeOf(obj, proto) {
var result = Object.create(proto);
var names = Object.getOwnPropertyNames(obj);
var getProp = Object.getOwnPropertyDescriptor;
var setProp = Object.defineProperty;
var length = names.length;
var index = 0;
while (index < length) {
var name = names[index++];
setProp(result, name, getProp(obj, name));
}
return result;
}
Così possiamo ora modificare il prototipo di un oggetto dopo che è creato come segue (presente che non sono effettivamente cambiando il [[proto]]
struttura interna dell'oggetto ma invece creare un nuovo oggetto con le stesse proprietà come oggetto dato e che eredita dalla proposta prototipo):
var a = {
b: "ok"
};
a = setPrototypeOf(a, {
a: "test"
});
alert(a.a); // alerts test
alert(a.b); // alerts ok
<script>
function setPrototypeOf(obj, proto) {
var result = Object.create(proto);
var names = Object.getOwnPropertyNames(obj);
var getProp = Object.getOwnPropertyDescriptor;
var setProp = Object.defineProperty;
var length = names.length;
var index = 0;
while (index < length) {
var name = names[index++];
setProp(result, name, getProp(obj, name));
}
return result;
}
</script>
Semplice ed efficiente (e non abbiamo utilizzato la proprietà __proto__
).
Sembra che "__proto__" possa essere standardizzato nel prossimo ECMAScript. Non posso essere assolutamente sicuro fino a quando non sarà finalizzato. http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts ... almeno è referenziato nella bozza attuale nell'Allegato B, Funzioni aggiuntive per i browser Web. –