Метод Object.setPrototypeOf() присвоює прототипу (тобто, внутрішній властивості [[Prototype]]) вказаного об'єкта інший об'єкт або null.
Застереження: Зміна властивості об'єкта [[Prototype]] за природою того, як сучасні рушії JavaScript оптимізують доступ до властивостей, є дуже повільною операцією у кожному переглядачі та рушії JavaScript. До того ж, ефект від зміни наслідування є неочевидним та обширним, і не обмежується лише часом, витраченим на інструкцію Object.setPrototypeOf(...), а може стосуватися будь-якого коду, що звертається до будь-якого об'єкта, чия властивість [[Prototype]] була змінена.
Оскільки ця функціональність є частиною мови, тягар її ефективної (в ідеалі) реалізації досі лежить на розробниках рушіїв. Поки розробники рушіїв не вирішать цю проблему, якщо вам важлива продуктивність, вам варто уникати присвоювати [[Prototype]] об'єкта. Замість цього, створіть новий об'єкт з бажаним значенням [[Prototype]], використовуючи Object.create().
Синтаксис
Object.setPrototypeOf(obj, prototype)
Параметри
obj- Об'єкт, прототипу якого треба присвоїти значення.
prototype- Новий прототип об'єкта (об'єкт або
null).
Значення, що повертається
Вказаний об'єкт.
Опис
Викидає виняток TypeError, якщо об'єкт, чия властивість [[Prototype]] змінюється, є нерозширюваним згідно з Object.isExtensible(). Не робить нічого, якщо параметр prototype не є об'єктом або null (число, рядок, булеве значення або undefined). Інакше, цей метод змінює значення [[Prototype]] об'єкта obj на нове значення.
Метод Object.setPrototypeOf() присутній у специфікації ECMAScript 2015. Він, загалом, вважається правильним способом встановлювати прототип об'єкта, у порівнянні з більш суперечливою властивістю Object.prototype.__proto__.
Приклади
var dict = Object.setPrototypeOf({}, null);
Поліфіл
Використовуючи більш стару властивість Object.prototype.__proto__, ми легко можемо визначити метод Object.setPrototypeOf, якщо він досі не є доступним:
if (!Object.setPrototypeOf) {
// Працює лише у Chrome та FireFox, не працює у IE:
Object.prototype.setPrototypeOf = function(obj, proto) {
if(obj.__proto__) {
obj.__proto__ = proto;
return obj;
} else {
// Якщо ви хочете повернути прототип Object.create(null):
var Fn = function() {
for (var key in obj) {
Object.defineProperty(this, key, {
value: obj[key],
});
}
};
Fn.prototype = proto;
return new Fn();
}
}
}
Додавання ланцюжків прототипів
Комбінація Object.getPrototypeOf() та Object.prototype.__proto__ дозволяє додавати цілі ланцюжки прототипів до нового прототипу:
/**
*** Object.appendChain(@object, @prototype)
*
* Додає перший невбудований прототип з ланцюжка до нового прототипу.
* Повертає @object (якщо це була проста величина, вона буде перетворена на об'єкт).
*
*** Object.appendChain(@object [, "@arg_name_1", "@arg_name_2", "@arg_name_3", "..."], "@function_body")
*** Object.appendChain(@object [, "@arg_name_1, @arg_name_2, @arg_name_3, ..."], "@function_body")
*
* Додає перший невбудований прототип з ланцюжка до вбудованого об'єкта Function.prototype,
* а потім додає new Function(["@arg"(s)], "@function_body") до цього ланцюжка.
* Повертає функцію.
*
**/
Object.appendChain = function(oChain, oProto) {
if (arguments.length < 2) {
throw new TypeError('Object.appendChain - Недостатньо аргументів');
}
if (typeof oProto !== 'object' && typeof oProto !== 'string') {
throw new TypeError("другий аргумент Object.appendChain повинен бути об'єктом або рядком");
}
var oNewProto = oProto,
oReturn = o2nd = oLast = oChain instanceof this ? oChain : new oChain.constructor(oChain);
for (var o1st = this.getPrototypeOf(o2nd);
o1st !== Object.prototype && o1st !== Function.prototype;
o1st = this.getPrototypeOf(o2nd)
) {
o2nd = o1st;
}
if (oProto.constructor === String) {
oNewProto = Function.prototype;
oReturn = Function.apply(null, Array.prototype.slice.call(arguments, 1));
this.setPrototypeOf(oReturn, oLast);
}
this.setPrototypeOf(o2nd, oNewProto);
return oReturn;
}
Використання
Перший приклад: Додавання ланцюжка до прототипу
function Mammal() {
this.isMammal = 'так';
}
function MammalSpecies(sMammalSpecies) {
this.species = sMammalSpecies;
}
MammalSpecies.prototype = new Mammal();
MammalSpecies.prototype.constructor = MammalSpecies;
var oCat = new MammalSpecies('Кіт');
console.log(oCat.isMammal); // 'так'
function Animal() {
this.breathing = 'так';
}
Object.appendChain(oCat, new Animal());
console.log(oCat.breathing); // 'так'
Другий приклад: Перетворення простого значення на екземпляр свого конструктора та додавання його ланцюжка до прототипу
function MySymbol() {
this.isSymbol = 'так';
}
var nPrime = 17;
console.log(typeof nPrime); // 'number'
var oPrime = Object.appendChain(nPrime, new MySymbol());
console.log(oPrime); // '17'
console.log(oPrime.isSymbol); // 'так'
console.log(typeof oPrime); // 'object'
Третій приклад: Додавання ланцюжка до об'єкта Function.prototype та додавання нової функції до цього ланцюжка
function Person(sName) {
this.identity = sName;
}
var george = Object.appendChain(new Person('Георгій'),
'console.log("Всім привіт!!");');
console.log(george.identity); // 'Георгій'
george(); // 'Всім привіт!!'
Специфікації
| Специфікація | Статус | Коментар |
|---|---|---|
| ECMAScript Latest Draft (ECMA-262) The definition of 'Object.setPrototypeOf' in that specification. |
Draft | |
| ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'Object.setPrototypeOf' in that specification. |
Standard | Початкове визначення. |
Сумісність з веб-переглядачами
| Desktop | Mobile | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
setPrototypeOf | Chrome Full support 34 | Edge Full support 12 | Firefox Full support 31 | IE Full support 11 | Opera Full support Yes | Safari Full support 9 | WebView Android Full support 37 | Chrome Android Full support 34 | Firefox Android Full support 31 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes | nodejs Full support 0.12 |
Legend
- Full support
- Full support