__proto__
was one of the most terrible mistakes.A Simple Dictionary Attack
ES6 says thatObject.create(null)
should not be affected anyhow from Object.prototype
.I've already mentioned this in the 5 Reasons You Should Avoid __proto__ post but I forgot to include an example.
You can test all this code with Chrome Canary or Firefox/Nightly and the most basic thing you need to know is this:
var n = Object.create(null); n.__proto__ = {}; for (var k in n) console.log(k); // __proto__ !!! Object.keys(n); // ["__proto__"] !!!Got it? So,
__proto__
is enumerable in some browser, is not in some other but it will be in all future browsers. Let's go on with examples ...
// store values grouped by same key function hanldeList(key, value) { if (!(key in n)) { n[key] = []; } n[key].push(value); } // the Dictionary as it is in ES6 var n = Object.create(null);Above code simply does not need to be aware of any problems except in older environment that won't work as expected. If the key is
__proto__
instead of storing the value there will be most likely an error or the object will inherit from an empty array the moment n[key] = []
will be executed.In few words, I believe you don't want to fear security and logic problems every single time you set a property to a generic object ... am I correct?
Now imagine some library such underscore.js, has the most common and generic way to create an object from another one, copying properties ...
function copy(obj) { var result = {}, key; for (key in obj) { if (obj.hasOwnProperty(key)) { result[key] = obj[key]; } } return result; } // or if you want ... function extend(a, b) { for (var key in b) { if (b.hasOwnProperty(key)) { a[key] = b[key]; } } return a; }Now guess what happens if you would like to copy or extend that list we had before, where
__proto__
will be own property for the n
variable and the loop is not checking the key as it should ... the object a
, or the new one, will automatically extend an Array and break completely its own expected behaviors ^_^This is nothing an explicit
Object.setPrototypeOf()
could cause ... moreover...Real World Performance Impact
Every utility such lo-dash or underscore should now do this kind of check per each loop if these would like to be considered safe:function copy(obj) { var result = {}, key; for (key in obj) { if ( obj.hasOwnProperty(key) && key !== '__proto__' ) { result[key] = obj[key]; } } return result; }Now try to investigate in your real-world daily code how many times you change
__proto__
compared with how many times you loop over properties ... I give you a test case to compare performance and remember: mobile matters!Really Hard To Debug
Being a special property in theObject.prototype
and not just a function you could wrap and keep under control, in a new scenario where any object could be instanceof
anything at any time, the inability to intercept __proto__
calls and changes before it happens will be a painful experience in terms of debugging ... what was that instance before? Most likely, you'll never know ^_^It must be said some engine makes that
descriptor.set
ter reusable but this is not the case of current V8, as example, neither the case for all mobile browsers out there today.A Stubborn Decision
What's driving me crazy about this property and all problems it brings, is that regardless there is a possible "speccable"Object.setPrototypeOf()
alternative that would not suffer from anything I've described in all these posts, and just as reminder there is already a spec'd and widely available Object.getPrototypeOf()
in ES5, TC39 will go on and make the problem a standardized one ^_^I haven't been able to reason against them regardless examples and reasons ... but you could have fun trying too before it's too late!