Object.setPrototypeOf()
method sets the prototype (i.e., the internal
[[Prototype]]
property) of a specified object to another object or
null
.
警告:
Changing the
[[Prototype]]
of an object is, by the nature of
how modern JavaScript engines optimize property accesses
, currently a very slow operation in every browser and JavaScript engine. In addition, the effects of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in the
Object.setPrototypeOf(...)
statement, but may extend to
any
code that has access to any object whose
[[Prototype]]
has been altered.
Because this feature is a part of the language, it is still the burden on engine developers to implement that feature performantly (ideally). Until engine developers address this issue, if you are concerned about performance, you should avoid setting the
[[Prototype]]
of an object. Instead, create a new object with the desired
[[Prototype]]
使用
Object.create()
.
Object.setPrototypeOf(obj, prototype)
obj
The object which is to have its prototype set.
prototype
null
).
The specified object.
抛出
TypeError
exception if the object whose
[[Prototype]]
is to be modified is non-extensible according to
Object.isExtensible()
. Does nothing if the
prototype
parameter isn't an object or
null
(i.e., number, string, boolean, or
undefined
). Otherwise, this method changes the
[[Prototype]]
of
obj
to the new value.
Object.setPrototypeOf()
is in the ECMAScript 2015 specification. It is generally considered the proper way to set the prototype of an object, vs. the more controversial
Object.prototype.__proto__
特性。
A combination of
Object.getPrototypeOf()
and
Object.prototype.__proto__
permits appending a whole prototype chain to a new prototype object:
/**
*** Object.appendChain(@object, @prototype)
*
* Appends the first non-native prototype of a chain to a new prototype.
* Returns @object (if it was a primitive value it will transformed into an 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")
*
* Appends the first non-native prototype of a chain to the native Function.prototype object, then appends a
* new Function(["@arg"(s)], "@function_body") to that chain.
* Returns the function.
*
**/
Object.appendChain = function(oChain, oProto) {
if (arguments.length < 2) {
throw new TypeError('Object.appendChain - Not enough arguments');
}
if (typeof oProto !== 'object' && typeof oProto !== 'string') {
throw new TypeError('second argument to Object.appendChain must be an object or a string');
}
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 = 'yes';
}
function MammalSpecies(sMammalSpecies) {
this.species = sMammalSpecies;
}
MammalSpecies.prototype = new Mammal();
MammalSpecies.prototype.constructor = MammalSpecies;
var oCat = new MammalSpecies('Felis');
console.log(oCat.isMammal); // 'yes'
function Animal() {
this.breathing = 'yes';
}
Object.appendChain(oCat, new Animal());
console.log(oCat.breathing); // 'yes'
function MySymbol() {
this.isSymbol = 'yes';
}
var nPrime = 17;
console.log(typeof nPrime); // 'number'
var oPrime = Object.appendChain(nPrime, new MySymbol());
console.log(oPrime); // '17'
console.log(oPrime.isSymbol); // 'yes'
console.log(typeof oPrime); // 'object'
function Person(sName) {
this.identity = sName;
}
var george = Object.appendChain(new Person('George'),
'console.log("Hello guys!!");');
console.log(george.identity); // 'George'
george(); // 'Hello guys!!'
Using the older
Object.prototype.__proto__
property, we can easily define
Object.setPrototypeOf
if it isn't available already:
if (!Object.setPrototypeOf) {
// Only works in Chrome and FireFox, does not work in IE:
Object.prototype.setPrototypeOf = function(obj, proto) {
if(obj.__proto__) {
obj.__proto__ = proto;
return obj;
} else {
// If you want to return prototype of Object.create(null):
var Fn = function() {
for (var key in obj) {
Object.defineProperty(this, key, {
value: obj[key],
});
}
};
Fn.prototype = proto;
return new Fn();
}
}
}
var dict = Object.setPrototypeOf({}, null);
| 规范 |
|---|
|
ECMAScript (ECMA-262)
The definition of 'Object.setPrototypeOf' in that specification. |
| Desktop | Mobile | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
setPrototypeOf
|
Chrome 34 | Edge 12 | Firefox 31 | IE 11 | Opera 21 | Safari 9 | WebView Android 37 | Chrome Android 34 | Firefox Android 31 | Opera Android 21 | Safari iOS 9 | Samsung Internet Android 2.0 | nodejs 0.12 |
完整支持
Reflect.setPrototypeOf()
Object.prototype.isPrototypeOf()
Object.getPrototypeOf()
Object.prototype.__proto__
Object
Object.assign()
Object.create()
Object.defineProperties()
Object.defineProperty()
Object.entries()
Object.freeze()
Object.fromEntries()
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.getPrototypeOf()
Object.is()
Object.isExtensible()
Object.isFrozen()
Object.isSealed()
Object.keys()
Object.preventExtensions()
Object.prototype.__defineGetter__()
Object.prototype.__defineSetter__()
Object.prototype.__lookupGetter__()
Object.prototype.__lookupSetter__()
Object.prototype.hasOwnProperty()
Object.prototype.isPrototypeOf()
Object.prototype.propertyIsEnumerable()
Object.prototype.toLocaleString()
Object.prototype.toSource()
Object.prototype.toString()
Object.prototype.valueOf()
Object.seal()
Object.setPrototypeOf()
Object.values()
Function