Difference between proto link and Object.create - javascript

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__.

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)

How does javascript know it has reached the end of __proto__ lookup chain

I am reading about the proto chain in javascript . I am trying to understand how javascript would know it has reached the end of __proto__ chain. Which will actually be inside the object pointed to by Object.prototype . So far I have grasped the following please correct me if I am wrong.
Every constructor function has a property called prototype and it also has a property called __proto__ by default __proto__ points to Object.prototype. However once an instance of an object is created using new, The __proto__ property of that instance is assigned a new value which is ConstructorName.prototype. Now during use when a property is not found in the local scope of the object. Javascript looks inside the object pointed to by __proto__ if the object is not found in there it then looks inside the object pointed to by the __proto__ of that object and the process continues. My question is now if the process continues it seems like eventually it will end up inside the object pointed to by Object.prototype. Does this Object.prototype have a __proto__ ?? I looked inside chrome and it seems it doesnt however it has getters and setters of proto so I am not sure about.that. I would like to know how this lookup ends.
Thank in advance.
Both of the following expressions are true:
console.log(Object.prototype.__proto__ === null);
console.log(Object.prototype.constructor === Object);
This means that the prototype chain via __proto__ ends when its value becomes null.
However, the constructor of Object.prototype is again Object, so that really is an endless loop. That, of course, is just the way it is implemented and does not mean that Object.prototype was created by new Object().
Prototype-less objects
You can also create an object which does not have a __proto__. These two expressions are true:
console.log(Object.create(null).__proto__ === undefined);
console.log(Object.create(null).constructor === undefined);
__proto__: both standardised and deprecated
A nice article on __proto__ mentions:
Because __proto__ was so widely supported, it was decided that its behavior should be standardized for ECMAScript 6. However, due to its problematic nature, it was added as a deprecated feature.
 
Object.getPrototypeOf()
For getting information about an object's prototype it is advised to use Object.getPrototypeOf(obj) instead of obj.__proto__:
console.log(Object.getPrototypeOf({}) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Object.getPrototypeOf(Object.create(null)) === null);

Confusion regarding javascript prototype explanation defined in Mozilla developer network

I have read about javascript prototype and read some stackoverflow question as well like how-does-javascript-prototype-work and I was finally understanding prototype properly but then as I was going through documentation on Mozilla Developer Netork (MDN) regarding prototype under this
Details_of_the_Object_Model MDN
Under that there is a note
Note: Directly assigning to FunctionName.prototype removes its original prototype's "constructor" property. As a result, (new WorkerBee).constructor yields "Employee" (instead of expected "WorkerBee"). Care must be taken to preserve the original prototype's constructor. For instance, assign the parent to FunctionName.prototype.__proto__ instead. For example, WorkerBee.prototype.__proto__ = new Employee; This way, (new WorkerBee).constructor yields expected "WorkerBee".
I can't seem to understand what this statement mean
Directly assigning to FunctionName.prototype removes its original prototype's "constructor" property.
Does it mean that Manager.prototype = new Employee will replace Manager.__proto__ = Function.prototype to Employee.prototype?
As a result, (new WorkerBee).constructor yields "Employee" (instead of expected "WorkerBee")
What does it mean that it will yield Employee? I know we should not directly use __proto__ but the above statement specify to use FunctionName.prototype.__proto__. In which case this is true?
Can someone explain with example what does it try to convey?
Prototype on functions are used as proto for objects generated by these functions.
A functions proto points to Function.prototype since a function is also an object instance by itself. Setting it's proto does not affect it's prototype but re setting it's prototype does affect the prototype. constructor
You should not set Child.prototype to an instance of Parent, use Object.create instead.
What prototype.constructor is and more is explained here: Prototypical inheritance - writing up

Javascript Closures vs Object.createProperty

My question is as follows : In most or all tutorials that I read about closures their first and foremost asset is described as them being able to define private members . For example , from the fabulous nettuts website : http://net.tutsplus.com/tutorials/javascript-ajax/digging-into-design-patterns-in-javascript/ .
My question is as follows - Why would you choose to create objects with closures , with their somewhat unnatural syntax , when you can use Object.definteProperty ? e.g
var o = {}; // Creates a new object
// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, "a", {value : 37,
writable : false,
enumerable : true,
configurable : true});
// 'a' property exists in the o object and its value is 37
I must admit both ways are much longer than traditional OOP languages , but isn't the second way more natural ?
Why then are closures so popular , what other assets do they have and what is the difference between creating an object with a closure or with the way I just described?
Object.defineProperty still defines public properties, while closures allow privacy (you should not talk of private "members", it's just local variables).
Your example, using defineProperty to define a enumerable, writable and configurable data property can (and should) be abbreviated by the default property assignment (which works in older browsers as well):
o.a = 37;
Not all objects need to be created with closures (and in your example I can't think of any application), but you might want to learn How do JavaScript closures work?.
It is a matter of syntax preference and browser compatibility. One big gotcha, is if you want browser compatible code, the defineProperty method is only available in IE 9+ for non-dom objects.
As far as syntax goes, you can see that you loose a bit of what I call "visual encapsulation" when using defineProperty.
Each way has its own benefits, but both lack the simplicity of a language which supports privacy more directly.
Note:
I am assuming by priavate you mean you are setting the writable property to false.
Reference
MDN: defineProperty

Object.preventExtensions actually allows mutation of __proto__?

I was browsing MDC about new functions added to Object. One of them, Object.preventExtensions, is said to prevent mutations to the object's prototype, which can be obtained by using Object.getPrototypeOf or __proto__.
On Chrome, however, it seems to simply allow mutations to the object's prototype. This can be confirmed by just executing the code on the relevant page:
// EXTENSION (only works in engines supporting __proto__
// (which is deprecated. Use Object.getPrototypeOf instead)):
// A non-extensible object's prototype is immutable.
var fixed = Object.preventExtensions({});
fixed.__proto__ = { oh: "hai" }; // throws a TypeError
I don't get this TypeError, and fixed.__proto__.oh === 'hai', so it has been set even though it should have been disallowed. I can also add it when coding like Object.getPrototypeOf(fixed).oh = 'hai'.
Does this mean Chrome has a different interpretation of this function? How can one prevent extensions to an object's prototype (in Chrome)?
Nope, Chrome and Mozilla both implement the standards part of the spec the same. Read carefully:
Object.preventExtensions only prevents
addition of own properties. Properties
can still be added to the object
prototype.
Everything to do with .__proto__ is non-standard, and Chrome can implement that differently. You showed only that Chrome implements details with .__proto__ differently, and in my opinion, more intuitively: The spec says that the prototype is still extensible, so it makes sense that you should still be able to mutate it. The question then becomes why did Mozilla implement it that way?
For example, the following code works the same on both Chrome and FF:
var fixed = Object.preventExtensions({});
Object.getPrototypeOf(fixed).p = 99;
fixed.p; // 99
Clearly the prototype is still mutable. That makes sense with Chrome's implementation of .__proto__.
So to prevent extensions of a prototype, do so separately:
var fixed = Object.preventExtensions({});
Object.preventExtensions(Object.getPrototypeOf(fixed));
Object.getPrototypeOf(fixed).p = 99; // TypeError: Can't add property p, object is not extensible
In ECMAScript 5, objects have a boolean internal property named [[Extensible]], this property is set to false when you call the Object.preventExtensions method, and after that, no new own properties can be added to the object.
On Chrome 14.0.786.0, the assignment to __proto__ throws a TypeError as you expect.
But remember that the __proto__ extension is non-standard, so it's behavior may vary, of course syntactically it is a "property assignment", but internally it doesn't "add an own property", it mutates the object's prototype, thing that is not possible to do by any standard method.
About the example of the Object.getPrototypeOf method you show us, it's simply retrieving the object's prototype, in the case of your fixed object, it's the Object.prototype object:
Object.getPrototypeOf(fixed) === Object.prototype; // true
So your example:
Object.getPrototypeOf(fixed).oh = 'hai'
Is equivalent to:
Object.prototype.oh === 'hai';

Categories

Resources