Метод 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