In Javascript, why can't we set prototypal inheritance arbitrarily? - javascript

With Crockford's definition:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
and ECMA-262's introduction of Object.create(), we now can set a new object a's hidden prototype property to point to another object b for pure prototypal inheritance. But it is limited to a new object, and Javascript still won't allow something like
a.__proto__ = b;
for an existing object a in the ECMA-262 Javascript specification. Is there a reason to limit it to a new object but not for existing objects?

According to the MDN __proto__ entry, ES6 will allow assigning to an object's [[Prototype]]. The article previously (since October 2010) said that the property was deprecated. It will likely be some years yet before that is useful on the web, particularly as it's very difficult to implement robustly in browsers that don't support it.
I expect that the __proto__ property will be read–only for built–in objects and for host objects that have it.
You'll have to ask Brendan Eich why the [[Prototype]] property was hidden and could only be set through a constructor, but I suspect that he wanted to keep JavaScript simple and not allow the kind of abuse handed out to eval.
As for Crockford's beget, it was first published as clone by Lasse Reichstein Nielsen as a way to clone objects and has since been replaced by ES5 Object.create.

One reason I can see is to avoid the possibility of circular references.

Related

Mdn Docs __proto__ vs __proto__ Accessor

In mdn's doc's for the prototype chain, it states
All objects inherit the Object.prototype.__proto__ setter, which can be used to set the [[Prototype]] of an existing object (if the __proto__ key is not overridden on the object).
It then goes on to say that
Object.prototype.__proto__ accessors are non-standard and deprecated. You should almost always use Object.setPrototypeOf instead.
Along with this example:
const obj = {};
// DON'T USE THIS: for example only.
obj.__proto__ = { barProp: 'bar val' };
obj.__proto__.__proto__ = { fooProp: 'foo val' };
console.log(obj.fooProp);
console.log(obj.barProp);
The part that is confusing is they start the docs out with this example:
const o = {
a: 1,
b: 2,
// __proto__ sets the [[Prototype]]. It's specified here
// as another object literal.
__proto__: {
b: 3,
c: 4,
},
};
Stating that,
{ __proto__: ... } syntax is different from the obj.__proto__ accessor: the former is standard and not deprecated.
How is { __proto__: ...} different from obj.__proto__? Both are properties of an object, and I'm not quite clear on what the difference is here.
It's just the way the syntax was designed. (See here and here.) Assigning to the __proto__ of an existing object is deprecated, but specifying a __proto__ at the point when the object is created is not.
One reason for why an object literal can have it but doing so with an already existing object is not recommended is because, as MDN says on the subject of changing an object's prototype:
Warning: 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 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. You can read more in JavaScript engine fundamentals: optimizing prototypes.
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]] using Object.create().
In well-designed code, there should not be a need to dynamically change the internal prototype of an already existing object. In contrast, it's completely normal to want to specify an internal prototype when creating an object initially.
(Setting a new internal prototype of an object can be done with setPrototypeOf, which is not recommended, and by assigning to the object's __proto__, which is not only not recommended, but deprecated as well)

Setting __proto__ to null and then re-setting it breaks instanceof in Javascript [duplicate]

This question already has an answer here:
__proto__ doesn't seem to work after a null assignment - bug or feature?
(1 answer)
Closed 7 years ago.
I came across some odd behaviour while messing around in JavaScript
function Class() {};
var a = {};
a.__proto__ = Class.prototype
a instanceof Class => true
Setting proto to null, and then re-assigning it the same value makes the instanceof operator return false rather than true.
a.__proto__ = null
a.__proto__ = Class.prototype
a instanceof Class => false
I'm directing your attention to: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in obj.proto = ... statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().
And
Warning: While Object.prototype.proto is supported today in most browsers, its existence and exact behavior has only been standardized in the ECMAScript 6 specification as a legacy feature to ensure compatibility for web browsers. For better support, it is recommended that only Object.getPrototypeOf() be used instead.
In short, you're breaking things and then asking why they're broken. __proto__ isn't meant to be altered, and there isn't a standardized behaviour, so you can't depend on it doing what you want.
What are you trying to do? What is your end goal?
[![2 protos][1]][1]
Although i'm not sure why you'd do any of this, the inspector shows that the object has two proto properties. That is also an oddity, considering that property names should be unique. If you want somewhat of a semi explanation (non explanation), the two proto properties mess with instanceOf

Difference between proto link and Object.create

I want to know the difference between __proto__ and Object.create method. Take this example:
var ob1 = {a:1};
var ob2 = Object.create(ob1);
ob2.__proto__ === ob1; // TRUE
This implies Object.create method creates a new object and sets __proto__ link to the object received as parameter.
Why don't we directly use __proto__ link instead of using create method ?
__proto__ is nonstandard and won't be supported everywhere. Object.create is part of the official spec and should be supported by every environment going forward.
It also is implemented differently in different places.
From Effective Javascript:
Environments differ for example, on the treatment of objects with a
null prototype. In some environments, __proto__ is inherited from
Object.prototype, so an object with a null prototype has no special
__proto__ property
Moving forward the accepted way to create objects and implement inheritance is the Object.create function, and if you do need to access the prototype, you'll want to use Object.getPrototypeOf These functions are standardized and should work the same in all modern environments
Why don't we directly use proto link instead of using create method ?
Because __proto__ is a non-standard property and therefore not necessarily available in every browser.
However it seemed to be considered for ES.next. More info: MDN - __proto__.

Is instantiating a object really just inheritance in some way in javascript?

I was reading a JavaScript book and as I was reading a chapter about inheritance, I wondered if every time you create a instance of a object is it really inheritance that happens, especially since they are similar.
Examples: Prototype Chaining - someObject.prototype = new someOtherObject();
Instantiating an object var myArray = new Array()
Similar right?
Additionally the book(JavaScript for web developers, By:Nicholas Zakas) stated, a link exists between an instance and a constructor's prototype.(The link is usually known as __proto__)
So can one argue that instantiating a object is like inheritance?
No. You are confused because one of the methods of accomplishing inheritance (viz. prototypal inheritance) takes, as the prototype, a given object. And one method of acquiring objects is via constructors.
In other words, there is nothing special about someObject.prototype = new SomeOtherObject(). You could just as well do
someObject.prototype = { myObjectLiteral: "isJustAsGoodAsYourConstructoredInstance" };
or even someObject.prototype = false. The two operations, very literally, have nothing to do with each other.
EDIT To address the quote OP found in his book:
"Recall the relationship between
constructors, prototypes, and
instances: each constructor has a
prototype object that points back to
the constructor, and instances have an
internal pointer to the prototype."
Unfortunately, this is misleading at best, and plain wrong at worst. Consider what "each constructor has a prototype object that points back to the constructor" would mean. It would mean that, for example,
Array.prototype === Array
Function.prototype === Function
function CustomConstructor() { }
CustomConstructor.prototype === CustomConstructor
But all of these statements output false if you type them in your console.
Now consider "instances have an internal pointer to the prototype." This is true, but does not fit with the terminology he is using. What this means is:
var myProto = {};
function CustomConstructor() { }
CustomConstructor.prototype = myProto; // inherit from the myProto object.
var x = new CustomConstructor(); // x is an "instance"
Object.getPrototypeOf(x) === myProto; // Object.getPrototypeOf fetches the "internal pointer"
But as you can see, I didn't inherit using a constructor, as I tried to point out above. Instantiating an object is not inheritance in any way. It is simply that the prototype property of constructors is how prototypal inheritance is accomplished, just like classical inheritance is accomplished by placing extends BaseClass after a class definition in Java. In turn, this difference is present because prototypal inheritance lets you inherit a prototype object instance, not a base class.
The JavaScript Garden has a few good sections that might help if you want more information. Relevant are "The Prototype," "Constructors," and "The instanceof Operator."
Without using objectType.inherits() if I got your concept of inheritance then it is if you take just the right part:
new someOtherObject()
This is instantiation of someOtherObject.
What happens here is you are creating an object of type someOtherObject that inherits structure from an empty object (provided you have not set a prototype on this). Because the default value of prototype is an empty object {}.
You are putting this object as prototype of someObject:
someObject.prototype = new someOtherObject();
Now if you create an instance of someObject this will happen:
You create someObject that inherits the structure of someOtherObject in that point in time, which inherits the structure of (empty)object when it has been instanced.
Maybe a better explanation is saying that the instance gets extended with the structure of its prototype at that point in time, and leave all of the inheriting wording aside, since just using that can mislead. Since classic inheritance uses base classes (types) and proto uses instances of those. Now it all depends on how you look at inheritance, which to argue about does not exists at all in javascript (object types are mutable at runtime) as by Karl Marx argues that real communism is not possible at all in the concept. If you agree with this last statement then comparing and asking about it does not matter, because neithercase is.

What modernizer scripts exist for the new ECMAScript 5 functions?

ECMAScript 5 has quite a few nice additions. John Resig has a good overview here. Here is a good ECMAScript 5 compatibility table.
A lot of this stuff can be "faked" for browsers that don't support these functions yet. Do you know of any scripts that can do this? I'm particularly interested in Object.create.
For example, Douglas Crockford's JSON script checks if JSON functions exist before creating them.
If there was more like the JSON one we could include them when we need to use the new functions.
Crockford recommends this kind of Object.create shim:
if (typeof Object.create != "function") {
Object.create = function (o) {
function F(){}
F.prototype = o;
return new F;
};
}
But please don't do this.
The problem with this approach is that ES5 Object.create has a signature of 2 arguments: first — an object to inherit from, and second (optional) — an object representing properties (or rather, descriptors) to add to newly created object.
Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.
What we have is an inconsistent implementation with 2 different behaviors. In environments with native Object.create, method knows how to handle second argument; in environments without native Object.create, it doesn't.
What are the practical implications?
Well, if there's some code (say, a third party script) that wants to use Object.create, it's rather reasonable for that code to do this:
if (Object.create) {
var child = Object.create(parent, properties);
}
— essentially assuming that if Object.create exists, it must conform to specs — accept second argument and add corresponding properties to an object.
But, with the above-mentioned shim, second argument is simply ignored. There's not even an indication of something going wrong differently. A silent failure, so to speak — something that's rather painful to detect and fix.
Can we do better?
Well, it's actually impossible to create a fully-conforming Object.create shim using only (standard) ES3 facilities. The best solution is to create a custom wrapper method.
There are, however, few alternative (less than optimal) things you can try:
1) Notify user about inability to work with second argument
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw Error('second argument is not supported');
}
// ... proceed ...
};
}
2) Try to handle second argument:
if (!Object.create) {
Object.create = function (parent, properties) {
function F(){}
F.prototype = parent;
var obj = new F;
if (properties) {
// ... augment obj ...
}
return obj;
};
}
Note that "properties" is an object representing property descriptors, not just property names/values, and is something that's not very trivial to support (some things are not even possible, such as controlling enumerability of a property):
Object.create(parent, {
foo: {
value: 'bar',
writable: true
},
baz: {
get: function(){ return 'baz getter'; },
set: function(value){ return 'baz setter'; },
enumerable: true
}
});
The other inconsistency in the original shim is that it doesn't take care of parent object being null.
var foo = Object.create(null);
This creates an object whose [[Prototype]] is null; in other words, object that doesn't inherit from anything, not even Object.prototype (which all native objects in ECMAScript inherit from).
foo.toString; // undefined
foo.constructor; // undefined
// etc.
This is, by the way, useful to create "proper" hash tables in ECMAScript.
It's possible to emulate this behavior, but only using non-standard extensions, such as "magical" __proto__ property (so implementation would be not very portable or robust). Solution to this problem is similar: either emulate ES5 implementation fully, or notify about inconsistency/failure.
es5-shim http://github.com/kriskowal/es5-shim/
This was part of the narwhal stand-alone javascript environment, but has been broken out on its own. It's pretty darn mature and precise.
es5 - JavaScript/EcmaScript 5 in 3 is a collection shared at BitBucket. Object.create in particular is an easy one to fake, made popular by Crockford et al, but improved on here by Justin Love, focussing on many ES5 parts.
If you don't mind learning the library and writing some code yourself, you can find some code implementations of the ECMAScript 5 library at
https://developer.mozilla.org/En/JavaScript/ECMAScript_5_support_in_Mozilla
For example, the code for Array.filter
And then Crockford has JSON.parse/stringify in json2.js
https://github.com/douglascrockford/JSON-js

Categories

Resources