Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 does for of get prototype values - how to check hasownproperty

Using for...in I always check hasOwnProperty (which I guess is a good argument for using Object.keys) like:

for (let a in obj) {
    if (obj.hasOwnProperty(a)) {
        //logic
    }
}

Do I need to do the same check when I use for...of and if so how should I do it?

According to the MDN page on for...of

While for...in iterates over property names, for...of iterates over property values

But it doesn't say anything about whether that iteration includes inherited properties or only instance properties. The explanation and example code given there only involve instance properties.

like image 209
pQuestions123 Avatar asked Nov 05 '15 20:11

pQuestions123


1 Answers

for...of iterates through an iterable object's iterator. In the ES6 specification, the function that produces an iterator for an object is identified on an object by the Symbol.iterator property; i.e., someObj[Symbol.iterator].

The iterator returned by Symbol.iterator for each iterable type is different, but generally speaking it will only iterate the values contained by the object that are meaningful relative to the type. For example:

  • The String iterator iterates each code point as a single-character string
  • The Map iterator iterates over the [[MapData]] internal slot of the Map, which is where key-to-value mappings are stored
  • The Array iterator only iterates over integer indexes (see %ArrayIteratorPrototype%.next)

Adding properties to the object's prototype is unlikely to affect the iterator's behavior, so in that respect is not necessary to test if the value comes from an own-property or not.

for..of and for..in are fundamentally different. for..in iterates over an object's properties, and it's sometimes necessary to ask questions about those properties, like whether they are inherited or not. for..of pumps values out of an iterator, which privately decides what values to return in what order. It's not necessarily meaningful to ask whether the result of a for..of iteration is from an inherited property or not, because it might not be from a property at all. (Case in point, for..of iteration of a Map returns values that are not exposed as properties.)


I can think of only one (tremendously strange) case in which an inherited property would affect the behavior of an Array iterator, if all the following were true:

  • if Array.prototype has a property with an integer name, and
  • that integer-named property is not set as an own-property on the instance being iterated, and
  • the instance's length is greater than that integer index's name

For example:

Array.prototype["7"] = "hello";   // why are you doing this?? :O
var a = [1,2,3]
a.length = 8;                     // why are you doing this?? D:
for(g of a) { console.log(g); }   // great job, you got strange results

In this extremely bizarre case, you would iterate over the inherited 7 property. That's literally the only case I can think of, though; other inherited properties will be ignored either because they don't have integer names, or because they're shadowed by an instance property with the same integer name, or because they are greater or equal to the instance's length.

like image 147
apsillers Avatar answered Sep 28 '22 03:09

apsillers