Object.setPrototypeOf(obj, proto)
made it into ES6.The section 15.2.3.2 speaks clearly:
15.2.3.2 Object.setPrototypeOf ( O, proto )Without going into details, the most basic polyfill woud be like this:
When thesetPrototypeOf
function is called with arguments O and proto, the following steps are taken:
- If Type(O) is not Object, then throw a TypeError exception.
- If Type(proto) is neither Object or Null, then throw a TypeError exception.
- Let status be the result of calling the [[SetInheritance]] internal method of O with argument proto.
- ReturnIfAbrupt(status).
- If status is false, then throw a TypeError exception.
- Return O.
(function(O,s){ O[s]||(O[s]=function(o,p){o.__proto__=p;return o}) }(Object,'setPrototypeOf'));If you want to go into details, the full reliable polyfill is hard to write down due all inconsistencies across JS engines out there where the __proto__ setter cannot be reused which means it's not possible to trust this magic over objects created from null.
All you need to do is forget __proto__ and use the suggested polyfill until the day __proto__ can simply disappear from those specs pages.
Enjoy!
This is a full polyfill with some extra info you might want to analyze, whenever ployfill is strictly true or false.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint devel: true, indent: 2 */ | |
// 15.2.3.2 | |
if (!Object.setPrototypeOf) { | |
Object.setPrototypeOf = (function(Object, magic) { | |
'use strict'; | |
var set; | |
function checkArgs(O, proto) { | |
if (typeof O !== 'object' || O === null) { | |
throw new TypeError('can not set prototype on a non-object'); | |
} | |
if (typeof proto !== 'object' && proto !== null) { | |
throw new TypeError('can only set prototype to an object or null'); | |
} | |
} | |
function setPrototypeOf(O, proto) { | |
checkArgs(O, proto); | |
set.call(O, proto); | |
return O; | |
} | |
try { | |
// this works already in Firefox and Safari | |
set = Object.getOwnPropertyDescriptor(Object.prototype, magic).set; | |
set.call({}, null); | |
} catch (o_O) { | |
if ( | |
// IE < 11 cannot be shimmed | |
Object.prototype !== {}[magic] || | |
// neither can any browser that actually | |
// implemented __proto__ correctly | |
// (all but old V8 will return here) | |
{__proto__:null}.__proto__ === void 0 | |
// this case means null objects cannot be passed | |
// through setPrototypeOf in a reliable way | |
// which means here a **Sham** is needed instead | |
) { | |
return; | |
} | |
// nodejs 0.8 and 0.10 are (buggy and..) fine here | |
// probably Chrome or some old Mobile stock browser | |
set = function(proto) { | |
this[magic] = proto; | |
}; | |
// please note that this will **not** work | |
// in those browsers that do not inherit | |
// __proto__ by mistake from Object.prototype | |
// in these cases we should probably throw an error | |
// or at least be informed about the issue | |
setPrototypeOf.polyfill = setPrototypeOf( | |
setPrototypeOf({}, null), | |
Object.prototype | |
) instanceof Object; | |
// setPrototypeOf.polyfill === true means it works as meant | |
// setPrototypeOf.polyfill === false means it's not 100% reliable | |
// setPrototypeOf.polyfill === undefined | |
// or | |
// setPrototypeOf.polyfill == null means it's not a polyfill | |
// which means it works as expected | |
// we can even delete Object.prototype.__proto__; | |
} | |
return setPrototypeOf; | |
}(Object, '__proto__')); | |
} |