Two ways of determining if object has property in JavaScript - javascript

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.

Related

Access to internal object fields in Js

Having this code
var a = {date : 12};
for(var t in a){
alert(t);
}
I have one alert with date property.
But everywhere (i.e. here) i see that it is needed to write :
for (var property in object) {
if (object.hasOwnProperty(property)) {
// do stuff
}
}
So why i don't see internal properties of object?
The for..in syntax iterates every property of the object, including those found on the prototype chain (if they are enumerable). This is usually not what you want, so the hasOwnProperty check is usually recommended.
In your case it's not necessary, as your plain object doesn't inherit any enumerable properties from the Object prototype (the only thing in its prototype chain)
Also, for..in gives you the property names (keys) of the object, if you're interested in the value of that particular property, you have to use the bracket notation, extending your example to this:
var a = {date : 12};
for(var t in a){
alert(a[t]);
}
In JavaScript there exists the 'prototype chain', a form of inheritance. If you were to add a property to the prototype of a, and then add your date property directly onto a, your for loop would find both those properties.
The hasOwnProperty checks whether the current property has been attached directly to the context object or whether it has been inherited through the prototype chain.
So in my example, if you had added a property to a's prototype, the hasOwnProperty condition would return false and you wouldn't "do stuff" with it.
I guess the best way to see it is through an example:
Object.prototype.aBaseProperty = 123;
var childObject = { date: 12 };
for (var property in childObject) {
console.log(property)
}
// output: date aBaseProperty
for (var property in childObject) {
if (childObject.hasOwnProperty(property)) {
console.log(property)
}
}
// output: date
Also, rather than doing the hasOwnProperty check, you might prefer
Object.keys(object).forEach(function(value, key) { ... });
Where Object.keys will only return own properties.

Properties with 'enumerable' flag are listed in for/in loop?

I am new to javascript and learning now. I have the below query regarding the for/in loop and the 'enumerable' attribute of javascript object property.
Consider the following code snippet:
var base = {x:1, y:2, z:3}
var derived = Object.create(base)
derived["a"]=4
for(var prp in derived) { console.log(prp, derived.propertyIsEnumerable(prp)) }
For the above code the output is:
a true
x false
y false
z false
As I understand that the inherited properties are not enumerable, and my question is why they are listed in for/in loop .
As per my understanding the output should be :
a true.
Please correct me if I am wrong?
From MDN:
Every object has a propertyIsEnumerable method. This method can determine whether the specified property in an object can be enumerated by a for...in loop, with the exception of properties inherited through the prototype chain.
for..in will iterate through any of the object's enumerable properties, but propertyIsEnumerable will only be true for the object's "own" enumerable properties, and false for inherited ones.

How to check property with hasOwnProperty?

Does hasOwnProperty() check user-created objects only?
var myObj = {};
myObj.hasOwnProperty('toString'); // returns false
I want to know that toString() is used in which prototype?
String.hasOwnProperty('toString');// it's too returns false
Object.hasOwnProperty('toString');// it's too returns false
So, how to check toString() or something else is of what in prototype chain?
And also,
var myArr = ['a','b','c'];
myArr.hasOwnProperty('length');
// returns true, why? but it is of Array or Object...
Does hasOwnProperty() checks only user created objects only?
It works on all objects which have that method available on their prototype chain (all objects except certain host objects, namely some IE objects, and objects created with Object.create(null), as well as a few other exotic ways).
String and Object don't have toString() on them directly by default (though you can assign itself, but this wouldn't be recommended).
They do, however, have it on their prototype chain. As the first property lookup matched is used and String is a constructor function, it will find it on Function.prototype. You can confirm this by executing...
String.toString == Function.prototype.toString
Other objects have their own toString(), depending on what makes the most sense in which context.
var myArr = ['a','b','c'];
myArr.hasOwnProperty('length');// returns true, why? but it is of Array or Object...
An array does have a length property directly on it.
If you want to know if an object has a property available on its prototype chain, you can use the in operator...
var hasProp = 'toString' in String;

I don't understand writable and configurable property attributes of Objects

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)

What does enumerable mean?

I was directed to MDN's for..in page when it said, "for..in Iterates over the enumerable properties of an object."
Then I went to the Enumerability and ownership of properties page where it said "Enumerable properties are those which can be iterated by a for..in loop."
The dictionary defines enumerable as countable, but I can't really visualize what that means. Could i get an example of something being enumerable?
An enumerable property is one that can be included in and visited during for..in loops (or a similar iteration of properties, like Object.keys()).
If a property isn't identified as enumerable, the loop will ignore that it's within the object.
var obj = { key: 'val' };
console.log('toString' in obj); // true
console.log(typeof obj.toString); // "function"
for (var key in obj)
console.log(key); // "key"
A property is identified as enumerable or not by its own [[Enumerable]] attribute. You can view this as part of the property's descriptor:
var descriptor = Object.getOwnPropertyDescriptor({ bar: 1 }, 'bar');
console.log(descriptor.enumerable); // true
console.log(descriptor.value); // 1
console.log(descriptor);
// { value: 1, writable: true, enumerable: true, configurable: true }
A for..in loop then iterates through the object's property names.
var foo = { bar: 1, baz: 2};
for (var prop in foo)
console.log(prop); // outputs 'bar' and 'baz'
But, only evaluates its statement – console.log(prop); in this case – for those properties whose [[Enumerable]] attribute is true.
This condition is in place because objects have many more properties, especially from inheritance:
console.log(Object.getOwnPropertyNames(Object.prototype));
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", /* etc. */]
Each of these properties still exists on the object:
console.log('constructor' in foo); // true
console.log('toString' in foo); // true
// etc.
But, they're skipped by the for..in loop because they aren't enumerable.
var descriptor = Object.getOwnPropertyDescriptor(Object.prototype, 'constructor');
console.log(descriptor.enumerable); // false
If you create an object via myObj = {foo: 'bar'} or something thereabouts, all properties are enumerable. So the easier question to ask is, what's not enumerable? Certain objects have some non-enumerable properties, for example if you call Object.getOwnPropertyNames([]) (which returns an array of all properties, enumerable or not, on []), it will return ['length'], which includes the non-enumerable property of an array, 'length'.
You can make your own non-enumerable properties by calling Object.defineProperty:
var person = { age: 18 };
Object.defineProperty(person, 'name', { value: 'Joshua', enumerable: false });
person.name; // 'Joshua'
for (prop in person) {
console.log(prop);
}; // 'age'
This example borrows heavily from Non-enumerable properties in JavaScript, but shows an object being enumerated over. Properties can either be or not be writable, configurable, or enumerable. John Resig discusses this in the scope of ECMAScript 5 Objects and Properties.
And, there's a Stack Overflow question about why you'd ever want to make properties non-enumerable.
It's a lot more boring than something that should be visualized.
There is literally an attribute on all properties called "enumerable." When it is set to false the for..in method will skip that property, pretend it doesn't exist.
There are a lot of properties on objects that have "enumerable" set to false, like "valueOf" and "hasOwnProperty," because it's presumed you don't want the JavaScript engine iterating over those.
You can create your own non-enumerable properties using the Object.defineProperty method:
var car = {
make: 'Honda',
model: 'Civic',
year: '2008',
condition: 'bad',
mileage: 36000
};
Object.defineProperty(car, 'mySecretAboutTheCar', {
value: 'cat pee in back seat',
enumerable: false
});
Now, the fact that there is even a secret about the car is hidden. Of course they can still access the property directly and get the answer:
console.log(car.mySecretAboutTheCar); // prints 'cat pee in back seat'
But, they would have to know that the property exists first, because if they're trying to access it through for..in or Object.keys it will remain completely secret:
console.log(Object.keys(car)); //prints ['make', 'model', 'year', 'condition', 'mileage']
They should have just called it, "forInAble."
I will write one line definition of ENUMERABLE
Enumerable: Specifies whether the property can be returned in a for/in loop.
var obj = {};
Object.defineProperties(obj, {
set1: {enumerable: true},
set2: {enumerable: false},
});
Object.keys(obj); // ["set1"]
Object.getOwnPropertyNames(obj); // ["set1", "set2"]
If you're having difficulty visualising "what does it mean to be enumerable?" why not ask yourself, what does it mean to be nonenumerable?
I think of it a bit like this, a nonenumerable property exists but is partially hidden; meaning that nonenumerable is the weird one. Now you can imagine enumerable as what is left - the more natural property we're used to encountering since we discovered Objects. Consider
var o = {};
o['foo'] = 0; // enumerable, normal
Object.defineProperty(o, 'bar', {value: 1}); // nonenumerable, weird
Now in a for..in, imagine it like pseudocode
for property in o:
if not property enumerable continue // skip non-enumerable, "bar"
else do /* whatever */ // act upon enumerable, "foo"
where the body of the loop you typed in JavaScript is in the place of /* whatever */
Built-in methods that objects inherit are not
enumerable, but the properties that your code adds to objects are enumerable unless explicitly stated
Think of the enum data type, just a structure of objects that correspond to different numbers. To declare something to as an enumerable is to declare that it corresponds to a specific number, allowing it to be given a place in a Dictionary that represents countable components of an object. To put it simply, making an object enumerable is the same as telling the compiler, "Hey, this property counts, I want to see this when I check for data on this object."
methods are not enumerable; or rather built in methods are not.. tho after searching on what enumerable means to java script; it just refers to a property attribute.. all created objects in ecma3 are enumerable, and ecma5 u can now define it....that's it.. :D lol took me a bit to find the answer; but I believe its talked about in David Flanagan's book.. so I guess it means "hidden", or not "hidden" in that methods are not shown in the for in loop, and thus are "hidden"

Categories

Resources