I don't understand the Writable and Configurable attributes of Objects. For example, in the MDN for Object.prototype, there is a table where I can clearly see that Configurable, Writable and Enumerable Property Attributes of Object.prototype are locked.
However, I can write and extend Object.prototype, for example with the following code:
// Example 1
Object.prototype.testing=999;
console.log(Object.testing); // 999
// Example 2
var o = {};
console.log(o.testing); // 999
What the MDN is referring to is the property prototype of Object itself. You cannot overwrite Object.prototype itself. If you try and make Object.prototype undefined, that will fail:
Object.prototype = 1;
console.log(Object.prototype); // [object Object]
If you try this in strict mode, you will get a TypeError upon attempting to assign to a non-writable property:
'use strict';
Object.prototype = 1; // TypeError: Cannot assign to read only property 'prototype' of function Object() { [native code] }
You can write to an object's own properties without changing what the object's reference is, and those have separate attributes. For example, see this:
var descriptor = Object.getOwnPropertyDescriptor(Object.prototype, 'toString');
console.log(descriptor.writable); // true
console.log(descriptor.enumerable); // false
console.log(descriptor.configurable); // true
There is a separate [[Extensible]] internal property that prevents the creation of new properties on an object -- this is set to false if you call Object.preventExtensions, Object.seal or Object.freeze.
Note that it's not a good idea to call Object.freeze on something like Object.prototype, as really weird things can happen:
Object.freeze(Object.prototype);
var building = {};
building.name = 'Alcove Apartments';
building.constructor = 'Meriton Apartments Pty Ltd';
console.log(building.constructor); // function Object() { [native code] }
Just like the previous example, it will also throw a TypeError in strict mode.
Basically, even though it would be a property on the object itself, it uses the attributes from the prototype chain to check whether or not it can assign the property. This has been considered as a mistake in the language by some people, however others consider this behaviour to be by design.
From: http://ejohn.org/blog/ecmascript-5-objects-and-properties/
Writable: If false, the value of the property can not be changed.
Configurable: If false, any attempts to delete the property or change its attributes (Writable, Configurable, or Enumerable) will fail.
Enumerable: If true, the property will be iterated over when a user does for (var prop in obj){} (or similar).
The Writable, Enumerable and Configurable attributes in MDN appear to be about the Object.prototype object itself, not its properties.
So, what that means is that you can't replace Object.prototype with a different object, but you are allowed to add properties to it.
So, what that means is if you do this:
Object.prototype = {foo: "whatever"}; // doesn't work - is just ignored
var j = {};
console.log(j.foo); // undefined
Then, the first line of code won't do anything.
I can clearly see that Configurable, Writable and Enumerable Property Attributes of Object.prototype are locked.
However, I can write Object.prototype.
No. The writability only concerns the prototype property of the Object object:
Object.prototype = {}; // Error: Invalid assignment (in strict mode)
// simply fails in lax mode
And I can extend Object.prototype
Yes. You can extend the Object.prototype object (regardless how you refer to it); that's a different attribute (of the object, not of a single property):
var proto = Object.getPrototypeOf({});
proto.testing1 = 9999; // works
Object.preventExtensions(proto);
proto.testing2 = 9999; // Error: Invalid assignment (in strict mode)
Related
I try to understand the following sentence at github airnb/javascript
https://github.com/airbnb/javascript#objects--prototype-builtins
Why? These methods may be shadowed by properties on the object in
question
What is meant with "shadowed" in this case?
For easier reference here the full section:
3.7 Do not call Object.prototype methods directly, such as hasOwnProperty, propertyIsEnumerable, and isPrototypeOf.
Why? These methods may be shadowed by properties on the object in
question - consider { hasOwnProperty: false } - or, the object may be
a null object (Object.create(null)).
// bad
console.log(object.hasOwnProperty(key));
// good
console.log(Object.prototype.hasOwnProperty.call(object,key));
// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
import has from 'has';
// ...
console.log(has.call(object, key));
When you creating an object
const anObject = {};
it almost always has the Object in prototype chain. It allow the created object to have access to functions defined in Object like hasOwnProperty.
Shadowed means a method or a property that defined in the created object has the same name as those functions or properties that in prototype chain.
Example of shadowing:
const obj = {};
obj.hasOwnProperty // => ƒ hasOwnProperty() { [native code] }
obj.hasOwnProperty = 'don\'t do this!';
obj.hasOwnProperty // => "don't do this!"
Consider some example below:
const object = { hasOwnProperty: false }
console.log(object.hasOwnProperty(key)) // Error: hasOwnProperty is not a function
or
const object = null
console.log(object.hasOwnProperty(key)) // Error: Can not read property of null
So you can understand shallowed in this case is your object methods in prototype is shallowed by an object property (has the same name)
See an example. Here I have created an function with name hasOwnProperty directly on the my object. So it hides the parent version of the hasOwnProperty. In it I write a logic which will return everytime true. So anybody who will use my object and tries to detect if it has some property in it (he/she doesn't know I have shadowed the base on) he can have a logic errors in his/her code. Because JS will try to find the function first in the object and call that version which actually does another work.
But when you call this method from the Object.prototype, which is the correct version of the method, and pass the context to it, it will work correctly, because it will call the Object.prototypes method with name hasOwnProperty and just pass this object as the context of the method. So from here is the warning that you must use this methods from the prototype.
Actually you can also change the Object.prototype version of the method, but there is a rule, Not change the prototypes of the built in objects.
const object = {
hasOwnProperty: function() {
return true;
}
};
console.log(object.hasOwnProperty('name'));
console.log(Object.prototype.hasOwnProperty.call(object, 'name'));
The first log says that there is a property name in the object, but it isn't. This may cause a logic error. The second one uses the correct version and gives a correct result.
I have been reading through Mozilla Developer Network lately on JavaScript inheritance model. I am highly confused on one point. Here's the code from MDN:
function Graph() {
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function(v) {
this.vertices.push(v);
}
};
var g = new Graph();
console.log(g.hasOwnProperty('vertices'));// true
console.log(g.hasOwnProperty('addVertex'));// false
console.log(g.__proto__.hasOwnProperty('addVertex'));// true
What I don't understand is that why does g.hasOwnProperty('addVertex') yields false since addVertex is a property of g although it's defined in Graph's prototype but still it is part of Graph.
Also I had one more question: that if some object inherits from g (or so to say Graph) will it inherit only addVertex (those defined in Prototype of function) or it will inherit all three properties of graph namely vertices, edges and addVertex.
why does g.hasOwnProperty('addVertex') yields false
That is the way hasOwnProperty works. From MDN:
The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as own (not inherited) property.
So hasOwnPropertydoes not traverse the prototype chain when do its checks.
You can use in operator to check property in prototype chain.
Because hasOwnProperty specifically says it return false on inherited properties
MDN:
The hasOwnProperty() method returns a boolean indicating whether the
object has the specified property as own (not inherited) property.
As for your second question - it depends on exactly how you have an object inherit from Graph. In the ES5 way, I would do this:
var InheritedFromGraph = function() {
Graph.call(this);
}
InheritedFromGraph.prototype = Graph.prototype;
and then, yes, InheritedGraph will get the properties verticies and edge that Graph defined in it's constructor.
Given this object:
var myObject = {
...
};
Is this method:
var hasProp = Object.keys(myObject).indexOf('myProp') !== -1;
The same as:
var hasProp = myObject.hasOwnProperty('myProp')
That is, will they result in the same value for hasProp, always?
I was asked this in an interview and the interviewer said they would yield different results but did not give me an example.
Thanks!
Any non-enumerable property breaks this symmetry. For example, fire up a Node.js console or use a compliant browser's console to perform both:
Object.keys([]); // yields []
[].hasOwnProperty('length'); // yields true.
because for arrays, the magic length property is marked as non-enumerable. There is another function which does all of them, even non-enumerables:
Object.getOwnPropertyNames([]) // yields [ 'length' ]
that is fully equivalent.
Object.keys "returns an array of a given object's own enumerable properties". hasOwnProperty works regardless of the fact that the property is enumerable or not.
See this example where hasOwnProperty is true yet Object.keys does not contain the property.
var obj = {};
Object.defineProperty(obj, "prop", {value: 1, enumerable: false});
obj.prop; // 1
obj.hasOwnProperty("prop"); // true
Object.keys(obj); // []
Object.keys(obj).indexOf('prop'); // -1
This uses the ECMAScript 5 defineProperty but non-enumerable properties also exist on basic objects. As shown by #ChrisDrost, the array's length is a non-enumerable property that does not show up in Object.keys yet responds true to hasOwnProperty.
Your code will not always return the same value for hasOwnProperty.
From Mozilla's Documentation on hasOwnProperty:
Example: Direct versus inherited properties
The following example differentiates between direct properties and
properties inherited through the prototype chain:
o = new Object(); o.prop = 'exists'; o.hasOwnProperty('prop'); // returns true
o.hasOwnProperty('toString'); // returns false
o.hasOwnProperty('hasOwnProperty'); // returns false
Which means that your method acts as a sort of hasOwnProperty that also checks for inherited attributes.
I think in practice, they act the same, but this a subtle difference.
I created a read only property on an object and the appropriate unit tests.
//works as expected
function OnSelf() {
this._val = 'test';
Object.defineProperty(this, 'test', {
enumerable: true,
configurable: false,
get: function () {
return this._val;
}
});
}
However, I realized that I should have been putting the readonly property on the prototype instead of each individual instance. I changed my code and then one of my tests failed.
//no exception when trying to delete the property
function OnPrototype() {
this._val = 'test';
}
Object.defineProperty(OnPrototype.prototype, 'test', {
enumerable: true,
configurable: false,
get: function () {
return this._val;
}
});
It appears that when deleting a read-only property on the prototype, no exception is thrown, but when the property is on the object, an exception is thrown.
var s = new OnSelf();
delete s.test; // throws error
var p = new OnPrototype();
delete p.test; // doesn't delete it, but no error occurs
I created http://jsfiddle.net/pdgreen/3BGfM/ to demonstrate the problem. I confirmed the same behavior on Mac with chrome and firefox.
Is this the correct thing to happen? Why if the property is on the object, an exception is thrown, but on the prototype, no exception? This surprises me. Can anyone explain why it is so?
That's the correct behavior you're seeing. The 'delete' keyword only deletes an object's own properties; it can't delete the object's prototype's properties. (And if it did, that would be terrible -- it would mess up any other objects inheriting from that same prototype!)
Try the following:
> function Constructor() {}
undefined
> Constructor.prototype.test = "Prototype";
"Prototype"
> var obj = new Constructor();
undefined
> obj.test
"Prototype"
> obj.test = "Child"
"Child"
> obj.test
"Child"
> delete obj.test
true
> obj.test
"Prototype"
The key to prototypical inheritance is that prototypes are actual objects containing their own properties, and that inheritance is fully live and dynamic. If an object doesn't define a property but an object in its prototype chain does, the child object inherits that value. When its value gets overridden locally, it now defines that property itself. If the child object's property gets deleted, the value from the prototype comes through again.
When the property is defined directly on the object, then the object has an "own" property that can be deleted. However, if the property is defined on the prototype, then there is no "own" property to delete, so the delete operation is a no-op. The property is actually on the prototype, (that is how prototypical inheritance works, the property isn't actually added to the object unless it is changed).
Figuring this out is a twisted maze of passages, all alike... also known as the ES5 spec, but the key section (after decoding your way to it) is 8.12.7, coupled with realizing that the GetOwnProperty internal method discussed in that section will return undefined in the prototype case.
Some projects use Object.create() or Object.defineProperties() function. I wonder is is recommended? Whats the difference between
x = Object.create(null);
vs
x = {}
And
x = {}
x.__proto__.hello = function() {
console.log("hello");
}
vs
x = Object.create(null);
Object.defineProperty(x, "hello", {
value: function() {
console.log("hello");
}
});
defineProperty/create seems very verbose and long to me. When/Why do I use them? Perhaps the good might be to enforce getters/setters/overriding properties?
There is a huge difference. Have a look at the docs!
Object.create does create an Object that inherits from the first argument, null in your case. In contrast, {} - or new Object() - creates a new object that inherits from Object.prototype.
__proto__ is non-standard and should not be used. However, in your case you just do Object.prototype.hello = function() {…};. Never extend that object with enumerable properties, never ever!
Object.defineProperty does define a property on an object with a special descriptor object. The enumerable, configurable and writable attributes default to false, which means that you wont be able to delete x.hello for example, or assign any other value.
Your first snippet creates a plain object, which inherits a hello method from Object.prototype, while your second snippet creates an object inheriting from nothing and having a non-editable hello property. I don't see much relatedness.