I read a book on JavaScript'у , there is such an example:

 Object.prototype.keys = function() { var keys = []; for(var p in this) keys.push(p); return keys; } var obj = {a: 1, b: 2, c: 3}; if(obj.keys().length == 3) { alert(1); } else { alert(2) } 

The bottom line is that the length property does not work correctly for some reason and I cannot figure out for what reason.

The following is an example where the check is added:

 Object.prototype.keys = function() { var keys = []; for(var p in this) if (this.hasOwnProperty(p)) keys.push(p); return keys; } var obj = {a: 1, b: 2, c: 3}; if(obj.keys().length == 3) { alert(1); } else { alert(2) } 

I can not understand how this test affected the result of the implementation.

In my understanding, in the second example, it checks whether the property is inherited from an object or not, and if not, then it is added to the array with the results, and if so, it is not added. But in the test object there are no inherited properties, in fact the result is the same should come out, but it is not. Explain, please.

  • “There are no inherited properties” - actually there is, stick console.log(p) into the loop and see for yourself - andreymal

2 answers 2

The error will become clearer if we display the result of the call to keys() .

 Object.prototype.keys = function() { var keys = []; for (var p in this) keys.push(p); return keys; } var obj = { a: 1, b: 2, c: 3 }; console.log(obj.keys()); 

As you can see, the new keys method is also recorded.

That it was not taken into account, it is necessary to change its enumerable modifier to false

You can make sure that it is true obtaining a property description , change an existing property, or you can create a new one using the Object.defineProperty method

 Object.prototype.keys = function() { var keys = []; for (var p in this) keys.push(p); return keys; } var keysProp = Object.getOwnPropertyDescriptor(Object.prototype, 'keys'); console.log(keysProp); keysProp.enumerable = false; // меняем существующее свойство Object.defineProperty(Object.prototype, 'keys', keysProp); var obj = { a: 1, b: 2, c: 3 }; console.log(obj.keys()); 
 .as-console-wrapper { max-height: none !important; } 

You can see more about traversing with For..in in the question: What is the principle of the FOR IN loop traversing an array?

    In the first case, keys contains both methods and properties (3 properties and the keys method itself), and has a length of 4. In the second case, keys contains only properties, and has a length of 3.