Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__proto__, when will it be gone? Alternatives?

Mozilla claimed it would remove __proto__ a while back (~2008) and it is still in the browser. Is it still going to be deprecated? It works in Opera, (Safari I think) and Chrome as well. I don't need to worry about IE so I would love to keep using it.

However, I don't want my code to stop working one day, so on to my question:

__proto__ allows for dead simple inheritance:

a.__proto__ = {'a':'test'}

Is there anyway I can replicate this in a standards compliant way? I know there is functional inheritance, that's ugly, and it over-complicates the fact that I just want to create a prototype chain. Just wondering if any wizards have solved this.

Thanks

like image 806
jdw Avatar asked May 07 '12 04:05

jdw


People also ask

Is __ proto __ deprecated?

__proto__ is considered outdated and somewhat deprecated (moved to the so-called “Annex B” of the JavaScript standard, meant for browsers only). The modern methods to get/set a prototype are: Object.

What is difference between __ proto __ and prototype?

prototype is a property of a Function object. It is the prototype of objects constructed by that function. __proto__ is an internal property of an object, pointing to its prototype. Current standards provide an equivalent Object.

What does __ proto __ mean in JavaScript?

Description. The __proto__ getter function exposes the value of the internal [[Prototype]] of an object. For objects created using an object literal, this value is Object. prototype . For objects created using array literals, this value is Array.

What is the purpose of the [[ prototype ]] property of objects?

Object's Prototype The prototype object includes following properties and methods. Returns a function that created instance. This is invisible property of an object. It returns prototype object of a function to which it links to.


2 Answers

Note: It's considered a bad practice to change the value of __proto__. Doing so is strongly discouraged by Brendan Eich, the creator of JavaScript, amongst others. In fact the __proto__ property has been removed entirely from a few JavaScript engines like Rhino. If you wish to know why then read the following comment by Brendan Eich.

Update: Browsers are not going to remove the __proto__ property. In fact, ECMAScript Harmony has now standardized both the __proto__ property and the setPrototypeOf function. The __proto__ property is only supported for legacy reasons. You are strongly advised to use setPrototypeOf and getPrototypeOf instead of __proto__.

Warning: Although setPrototypeOf is now a standard, you are still discouraged from using it because mutating the prototype of an object invariably kills optimizations and makes your code slower. In addition, the use of setPrototypeOf is usually an indication of poor quality code.


You don't need to worry about your existing code not working one day. The __proto__ property is here to stay.

Now, for the question at hand. We want to do something similar to this in a standards compliant way:

var a = {
    b: "ok"
};

a.__proto__ = {
    a: "test"
};

alert(a.a); // alerts test
alert(a.b); // alerts ok

Obviously you can't use Object.create to achieve this end since we are not creating a new object. We are just trying to change the internal [[proto]] property of the given object. The problem is that it's not possible to change the internal [[proto]] property of an object once it's created (except via using __proto__ which we are trying to avoid).

So to solve this problem I wrote a simple function (note that it works for all objects except for functions):

function setPrototypeOf(obj, proto) {
    var result  = Object.create(proto);
    var names   = Object.getOwnPropertyNames(obj);
    var getProp = Object.getOwnPropertyDescriptor;
    var setProp = Object.defineProperty;
    var length  = names.length;
    var index   = 0;

    while (index < length) {
        var name = names[index++];
        setProp(result, name, getProp(obj, name));
    }

    return result;
}

So we can now change the prototype of any object after it's created as follows (note that we are not actually changing the internal [[proto]] property of the object but instead creating a new object with the same properties as the given object and which inherits from the given prototype):

var a = {
    b: "ok"
};

a = setPrototypeOf(a, {
    a: "test"
});

alert(a.a); // alerts test
alert(a.b); // alerts ok
<script>
function setPrototypeOf(obj, proto) {
    var result  = Object.create(proto);
    var names   = Object.getOwnPropertyNames(obj);
    var getProp = Object.getOwnPropertyDescriptor;
    var setProp = Object.defineProperty;
    var length  = names.length;
    var index   = 0;

    while (index < length) {
        var name = names[index++];
        setProp(result, name, getProp(obj, name));
    }

    return result;
}
</script>

Simple and efficient (and we didn't use the __proto__ property).

like image 172
Aadit M Shah Avatar answered Sep 23 '22 15:09

Aadit M Shah


I think the actual point Mozilla wanted to make is that it's nonstandard, so the implementors would be perfectly within their rights removing it.

The cleaner way to do prototype chains is Object.create. The equivalent of your code, to create an object a with the prototype {'a': 'test'}, is:

a = Object.create({'a':'test'})

There are also shims to mimic this function in browsers that don't support it, if you ever need to work with one, which is another advantage over directly messing around with __proto__.

like image 27
Chuck Avatar answered Sep 22 '22 15:09

Chuck