Only custom object properties are shown during for-in loop - javascript

Array.prototype.myFeature = function() {};
var arr = ['some', 'items'];
for (var prop in arr) {
console.log(prop);
}
The output for that code will be: 0, 1, myFeature.
The question is: why only custom added function to the Array prototype is outputed, instead of all the function that exists in prototype?

This is because built-in array methods are defined to be non-enumerable, while properties created by ordinary assignment are enumerable. Internally, properties have behavioral features specified by their associated property descriptor which is defined at property-creation time. One feature supplied in this way is the property's enumerability.
Compare
> Object.getOwnPropertyDescriptor(Array.prototype, "join")
{value: ƒ, writable: true, enumerable: false, configurable: true}
and
> Object.getOwnPropertyDescriptor(Array.prototype, "myFeature")
{value: ƒ, writable: true, enumerable: true, configurable: true}
The first property descriptor object has enumerable: false while the second has enumerable: true. Non-enumerable properties are not enumerated in for-in loops.
You can define your own non-enumerable property with Object.defineProperty:
Object.defineProperty(Array.prototype, "myFeature", { value: function() {}, enumerable: false });

Per the docs:
The for...in statement iterates over the enumerable properties of an object. For each distinct property, statements can be executed.
Seems, only these three properties are enumerable. So for...in only iterates over them.

Related

Desciptor values are true

let obj = {windows : 10,wheels : 100,seats : 99};
console.log(Object.getOwnPropertyDescriptor(obj, 'wheels'))
Output:
Object { value: 100, writable: true, enumerable: true, configurable: true }
I read on an article that the default values of an object's descriptor are false, but the following code shows otherwise. Can someone tell me the mistake?
I read on an article that the default values of an object's descriptor are false...
That's only when you call Object.defineProperty or its cousin defineProperties (or use the second argument of Object.create), the defaults for the flags in the descriptor object are all false:
let obj = {};
Object.defineProperty(obj, "wheels", {
value: 100,
});
console.log(Object.getOwnPropertyDescriptor(obj, "wheels"))
When you create a property via direct assignment as you are in the question, they all default to true.

Why would an Object prototype method override String and Number prototype methods in JavaScript?

Trying to define a hashCode method on Object.prototype as well as String.prototype and Number.prototype. I'm defining the prototype methods using:
Object.defineProperty(Object.prototype, 'hashCode', {
value:function() {/*code*/},
enumerable:false
});
String.prototype.hashCode = function() {/*code*/};
Number.prototype.hashCode = function() {/*code*/};
When I create a number or string with any of ('', new String(), 3, new Number()), and call hashCode on the instance, the Object.prototype.hashCode method always runs instead of String.prototype.hashCode or Number.prototype.hashCode.
What's wrong?
Make the property descriptor writable: true or it will be inherited as non-writable when writing that property on objects that inherit it.
http://jsfiddle.net/5ox1a0f2 – squint
Object.defineProperty(Object.prototype, 'hashCode', {
value:function() {console.log('object')},
enumerable:false,
writable:true
});
String.prototype.hashCode = function() {console.log('string')};
Number.prototype.hashCode = function() {console.log('number')};
4..hashCode()
Mixing property definitions and property assignments can lead to this kind of problems.
It works if you also use property definition in String.prototype and Number.prototype:
Object.defineProperty(Object.prototype, 'hashCode', {
value: function() {console.log('object')},
enumerable: false
});
Object.defineProperty(String.prototype, 'hashCode', {
value: function() {console.log('string')},
enumerable: false
});
Object.defineProperty(Number.prototype, 'hashCode', {
value: function() {console.log('number')},
enumerable: false
});
(4).hashCode(); // "number"
('').hashCode(); // "string"
However, if you are only using property definitions because you don't want enumerability, but don't care about configurability nor writability, it may be more convenient to define the methods via assignment, and then redefine the enumerability:
Object.prototype.hashCode = function() {console.log('object')};
String.prototype.hashCode = function() {console.log('string')};
Number.prototype.hashCode = function() {console.log('number')};
Object.defineProperty(Object.prototype, 'hashCode', {enumerable: false});
Object.defineProperty(String.prototype, 'hashCode', {enumerable: false});
Object.defineProperty(Number.prototype, 'hashCode', {enumerable: false});
(4).hashCode(); // "number"
('').hashCode(); // "string"

Javascript : How to keep defined object descriptor of original objects after mixing them up?

let say i have thoses two objects for wich i set descriptor on each props :
var readonly = {
libName: _libName,
libVersion: _libVersion,
createStage: _createStage,
renderer: _renderer
};
Object.keys(readonly).forEach(function (prop) {
Object.defineProperty(readonly, prop, {
writable: false
});
});
and
var writable = {
rendererOptions: _rendererOptions
};
Object.keys(writable).forEach(function (prop) {
Object.defineProperty(writable, prop, {
writable: false
});
});
I then want to merge the two object with assign, but the descriptor are not kept. I don't know if its normal, as a third object is created. If so, how could i work that up to keep the descriptor? Here is what i am getting (this is only an example BTW) :
console.log(Object.getOwnPropertyDescriptor(writable, "rendererOptions"));
//gives Object {value: Object, writable: false, enumerable: true, configurable: true}
var o = Object.assign(readonly, writable);
console.log(Object.getOwnPropertyDescriptor(o, "rendererOptions"));
//gives Object {value: Object, writable: true, enumerable: true, configurable: true}
Thanks for any help you can give. And if you have a better solution, 'am all for it.
Here's my comment as an answer:
Seems like you're looking for something like the completeAssign example under MDN's article on Object.assign. The article should also help explain the behavior that you're seeing from the code above

why don't javascript object property descriptors always default to false (as per spec)

According to the spec when adding a javascript object property, the following defaults will be applied to property descriptors:
configurable: false
enumerable: false
writable: false
However when assigning an object property using the following (very popular) dot notation method they all default to true.
myObject = {};
myObject.a = 1;
Why is this?
Apparently - again according to a non-obvious part of the spec - it is due to the way the object property is defined.
See here
If an object property is defined using the dot notation method:
var myObject={};
myObject.a=1;
then all property descriptors default to true
If an object property is defined using the bracket notation method:
var myObject = {};
myObject["a"] = 1;
then all property descriptors default to true
However if an object property is defined using the defineProperty method:
var myObject={};
Object.defineProperty(myObject, 'a', { value: 1 });
any undefined descriptors default to false.
See an example in this jsfiddle
This is an issue that confuse a lot of new developers/programmers/engineers. There are two methods that contribute to this issue in the MDN. If you look at the Object.getOwnPropertyDescriptor() method in the MDN. It says that writable, enumerable, and configurable all default to false, but when you use the method all will return true (Yes, they are false by default).
Example:
let user = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log( JSON.stringify(descriptor, null, 2 ) );
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
Now, If you use the Object.defineProperty() method then you will see that the special property attributes are set to false by default. In the example below you will notice, because I didn't set an special attributes all of the properties are false by default.
Example:
let user = {};
Object.defineProperty(user, "name", {
value: "John"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "John",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
I know this is confusing for most people that are new to JavaScript, but I wouldn't try to overthink it. Keep it Simple...

how do javascript get property value

Through the following code I can get a plugin object in chrome browser:
nav = window.navigator;
detectPlugin = function(pluginName, mimeType) {
return nav.plugins && nav.plugins[pluginName] && nav.mimeTypes && nav.mimeTypes[mimeType] && nav.mimeTypes[mimeType].enabledPlugin ? nav.plugins[pluginName] : false;
};
obj = detectPlugin('Shockwave Flash', 'application/x-shockwave-flash');
And I can see the obj's properties through
Object.keys(obj)
which is
["0", "1", "length", "description", "filename", "name"]
or I can see these through chrome Console:
Plugin {0: MimeType, 1: MimeType, length: 2, description: "Shockwave Flash 13.0 r0", filename: "libpepflashplayer.so", name: "Shockwave Flash", item: function…}
And here is something that I don't understand, if I input
obj['application/x-shockwave-flash']
I get this
MimeType {enabledPlugin: Plugin, description: "Shockwave Flash", suffixes: "swf", type: "application/x-shockwave-flash"}
I know obj[0] is the property of 'MimeType', but I don't know why "obj['application/x-shockwave-flash']" can get this.
Any help would be great!
Object.keys only returns
a given object's own enumerable properties
i.e. if it's inherited or non-enumberable, you won't see it
What does it mean for a property to be enumerable?
In JavaScript, you can think of it as similar to meaning "the property is visible to loops"
What does it mean for a property to be inherited?
An Object inherits properties and methods from it's prototype, this means you can have very generic Objects, e.g. {} instanceof Object; // true and very complicated ones like d = new Date(), where d instanceof Date; // true but it still has everything the from the more generic Object, i.e. d instanceof Object; // true
Consider this (assuming IE 9+)
var o = {};
Object.defineProperty(o, 'foo', {value:"bar", enumerable:false});
Object.keys(o); // []
o.foo; // "bar"
And
navigator.plugins[0].hasOwnProperty('application/x-shockwave-flash'); // true
Object.getOwnPropertyDescriptor(
navigator.plugins[0],
'application/x-shockwave-flash'
);
//Object {value: MimeType, writable: true, enumerable: false, configurable: true}
The MDN page here may be helpful in understanding enumerability and ownership

Categories