Skip to content

Commit

Permalink
Add __proto__ key initializer to "Inheritance and the prototype chain" (
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh-Cena authored May 17, 2022
1 parent df0de32 commit 1e818c7
Showing 1 changed file with 80 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,13 @@ function f() {
// Functions inherit from Function.prototype
// (which has methods call, bind, etc.)
// f ---> Function.prototype ---> Object.prototype ---> null

const p = { b: 2, __proto__: o };

// It is possible to point the newly created object's [[Prototype]] to
// another object via the __proto__ literal property. (Not to be confused
// with Object.prototype.__proto__ accessors)
// p ---> o ---> Object.prototype ---> null
```
### With a constructor
Expand Down Expand Up @@ -396,7 +403,7 @@ Note: It is **not** enough to check whether a property is [`undefined`](/en-US/d
### Summary of methods for extending the prototype chain
Here are all 4 ways and their pros/cons. All of the examples listed below create exactly the same resulting `inst` object (thus logging the same results to the console), except in different ways.
Here are all 5 ways and their pros/cons. All of the examples listed below create exactly the same resulting `inst` object (thus logging the same results to the console), except in different ways.
#### #1: New initialization
Expand Down Expand Up @@ -480,7 +487,7 @@ const proto = Object.create(
bar.prototype = proto;
const inst = new bar();
console.log(inst.foo_prop);
console.log(inst.bar_prop)
console.log(inst.bar_prop);
```
<table class="standard-table">
Expand Down Expand Up @@ -540,7 +547,7 @@ const proto = Object.setPrototypeOf(
bar.prototype = proto;
const inst = new bar();
console.log(inst.foo_prop);
console.log(inst.bar_prop)
console.log(inst.bar_prop);
```
<table class="standard-table">
Expand All @@ -559,28 +566,30 @@ console.log(inst.bar_prop)
<tr>
<th scope="row">Con(s)</th>
<td>
Ill-performing. Should be deprecated. Many browsers optimize the
prototype and try to guess the location of the method in memory when
calling an instance in advance; but setting the prototype dynamically
disrupts all those optimizations. It might cause some browsers to
recompile your code for de-optimization, to make it work according to
the specs. Not supported in IE8 and below.
Ill-performing. Should be avoided if it's possible to set the prototype
at object creation time. Many browsers optimize the prototype and try to
guess the location of the method in memory when calling an instance in
advance; but setting the prototype dynamically disrupts all those
optimizations. It might cause some browsers to recompile your code for
de-optimization, to make it work according to the specs. Not supported
in IE8 and below.
</td>
</tr>
</tbody>
</table>
#### #4: Setting the {{jsxref("Object/proto","__proto__")}} property
> **Warning:** `Object.prototype.__proto__` accessors are **non-standard** and deprecated. You should almost always use `Object.setPrototypeOf` instead.
```js
// Technique 1
function A() {}
A.prototype.foo_prop = 'foo val';
function bar() {}
const proto = {
bar_prop: 'bar val',
__proto__: A.prototype
};
const proto = { bar_prop: 'bar val' };
// DON'T USE THIS: for example only.
proto.__proto__ = A.prototype;
bar.prototype = proto;
const inst = new bar();
console.log(inst.foo_prop);
Expand All @@ -589,17 +598,12 @@ console.log(inst.bar_prop);
```js
// Technique 2
const inst = {
__proto__: {
bar_prop: 'bar val',
__proto__: {
foo_prop: 'foo val',
__proto__: Object.prototype
}
}
};
const inst = {};
// DON'T USE THIS: for example only.
inst.__proto__ = { bar_prop: 'bar val' };
inst.__proto__.__proto__ = { foo_prop: 'foo val' };
console.log(inst.foo_prop);
console.log(inst.bar_prop)
console.log(inst.bar_prop);
```
<table class="standard-table">
Expand All @@ -624,7 +628,59 @@ console.log(inst.bar_prop)
instance in advance; but setting the prototype dynamically disrupts all
those optimizations and can even force some browsers to recompile for
de-optimization of your code, to make it work according to the specs.
Not supported in IE10 and below.
Not supported in IE10 and below. The {{jsxref("Object/proto","__proto__")}}
setter is normative optional, so it may not work across all platforms.
You should almost always use {{jsxref("Object.setPrototypeOf")}}
instead.
</td>
</tr>
</tbody>
</table>
#### #5: Using the `__proto__` key in object initializers
> **Note:** This is not to be confused with the aforementioned `Object.prototype.__proto__` accessors. `__proto__` in object literals is standardized and optimized.
```js
const inst = {
__proto__: {
bar_prop: 'bar val',
__proto__: {
foo_prop: 'foo val',
// This can be omitted
__proto__: Object.prototype
}
}
};
console.log(inst.foo_prop);
console.log(inst.bar_prop);
```
<table class="standard-table">
<caption>
Pros and cons of using the <code>__proto__</code> key in <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">object initializers</a>
</caption>
<tbody>
<tr>
<th scope="row">Pro(s)</th>
<td>
Supported in all modern browsers. Pointing the <code>__proto__</code>
key to something that is not an object only fails silently without
throwing an exception. Contrary to the
{{jsxref("Object/proto", "Object.prototype.__proto__")}} setter,
<code>__proto__</code> in object literal initializers is standardized
and optimized, and can even be more performant than
{{jsxref("Object.create")}}. Declaring extra own properties on the
object at creation is more ergonomic than
{{jsxref("Object.create")}}.
</td>
</tr>
<tr>
<th scope="row">Con(s)</th>
<td>
Not supported in IE10 and below. Likely to be confused with
{{jsxref("Object/proto", "Object.prototype.__proto__")}} accessors for
people unaware of the difference.
</td>
</tr>
</tbody>
Expand Down

0 comments on commit 1e818c7

Please sign in to comment.