How to Define Method in JavaScript on Array.Prototype and Object.Prototype So That It Doesn't Appear in For in Loop

How to define method in javascript on Array.prototype and Object.prototype so that it doesn't appear in for in loop

It's quite easy: Don't use for-in loops with Arrays. Blame everybody else who does so - here is a nice snippet to tell them during development.

Of course, if one does an enumeration in a generic function and doesn't know whether he gets an array, a plain object or an object with a custom prototype, you can use hasOwnProperty like this:

for (var prop in anyObj )
if (Object.prototype.hasOwnProperty.call(anyObj, prop))
// do something

Notice the explicit use of Object.prototype to get the function - there might be objects that overwrite it (especially in data-maps, the value might not even be a function), objects that do not support it or objects that do not inherit from Object.prototype at all. See also here.

Yet, only a script author who is aware of the problem would filter all his for-in-loops - and some only do it because it gets recommended - and does it mostly wrong, he should have used a for-loop array iteration instead. But our problem are those authors who do not know of it.

An interesting, but Mozilla-only approach would be overwriting the behavior of enumerations on arrays via __iterate__, as demonstrated here.

Fortunately, EcmaScript 5.1 allows us setting properties to be non-enumerable. Of course, this is not supported in older browsers, but why bother? We'd need to use es5-shims anyway for all the cool higher-order array stuff :-) Use defineProperty like this:

Object.defineProperty(Array.prototype, "find", {
enumerable: false,
writable: true,
value: function(testFun) {
// code to find element in array
}
});

Javascript: hiding prototype methods in for loop?

You can use JavaScript's hasOwnProperty method to achieve this in the loop, like this:

for(var key in arr) {
if (arr.hasOwnProperty(key)) {
...
}
}

Reference: This YUI blog article.

Javascript for ... in loop with Object.prototype and Array.prototype properties

It's because a for in loop is meant to iterate all enumerable properties, both owned and inherited. You can use Object.keys() to get only owned properties.

Object.prototype.objCustom = function() {}; 

Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];

iterable.foo = 'hello';

Object.keys(iterable).forEach(function(key) {

console.log(key); // logs 0, 1, 2, "foo"

});

Why does the function name appears in for loop while defining a function for Javascript prototype?

A for ... in loop will go through every one of the object's enumerable properties. So it will go through the ['1'] property, and the ['2'] property, etc. Among the properties that the array has is a function named ['contains']. Why does it have that? Because you put it there! :)

Or more accurately, you put it on its prototype. But that's pretty much the same as far as for ... in is concerned. It will loop through all the enumerable properties on the object, and also the enumerable properties it inherits from its prototype, and from its prototype's prototype, etc. There are plenty of properties on Array.prototype, but they're not enumerable (which is why it's not also logging out 'push', 'pop', 'map', etc). The one you put there is enumerable, because that's the default nature of properties.

As you pointed out, for ... in is not appropriate for traversing an array, so i would recommend changing the code to do something else. Could be a manual for loop, or this.forEach, or a for ... of for example.

Below this line are some other options, but they get a bit into the weeds with code that you'll rarely ever write (but then again, modifying Array.prototype is something you'll rarely ever do).

========

If you wanted to keep the for ... in loop, one option would be to explicitly check to make sure that each property you're looking at is from the object itself, not from its prototype. To do that, you can use hasOwnProperty. If the property came from the prototype, hasOwnProperty will return false. If the property is of this specific object, it returns true;

if (!Array.prototype.contains){

Array.prototype.contains = function(target){

for (var i in this){

if (!this.hasOwnProperty(i)) continue;

console.log(i);

if (this[i] == target) return true;

}

return false;

}

}

[1, 2].contains(5)

Is it ok to define a prototype function on Object in Javascript?

The only safe way to add to Object.prototype is to use the ES5 method Object.defineProperty to create a non-enumerable property:

Object.defineProperty(Object.prototype, 'doSomething', {
value: function(p) { ... },
enumerable: false, // actually the default
});

This ensures that the new property doesn't appear if you do for (key in object).

Note that this function cannot be reliably shimmed because non-enumerable properties didn't exist in previous versions of ECMAScript / JavaScript.

In any event, if your method only applies to HTML page elements, you would be better adding this to Element.prototype instead of to Object.prototype, although older (IE) browsers may complain if you do this.

Adding function to Object prototype causes function to show up in all 'for X in OBJ' loops

Which is why you should always check hasOwnProperty:

for (var temp in tempObject) {
if (Object.prototype.hasOwnProperty(tempObject, temp)) {
console.log(temp);
}
}

Crockford advocates using Object.prototype.hasOwnProperty instead of tempObject.hasOwnProperty, just in case you override hasOwnProperty in your object.


In ES5, you can set it to not be enumerable:

Object.defineProperty(Object.prototype, 'simpleFunction', {
value: function() {
return true;
},
enumerable: false, // this is actually the default
});

Alternatively (in ES5), you can use Object.keys() to only get the object's own keys:

Object.keys(tempObject).forEach(function(key) {
console.log(key);
});


Related Topics



Leave a reply



Submit