Can you make properties enumerable but not repeatable in javascript?

I'm just wondering if there is a way to make the property of an object enumerable, like in a for in loop, but not display as a for of loop like

 Object.defineProperty({},'prop',{ enumerable:true, iterable:false } 

If not, do you plan to implement such a function? Or the for of property uses an enumeration property

+6
source share
2 answers

I did a bit of work on the Mozilla Development Network (MDN).

It turns out that objects have an obj.propertyIsEnumerable(prop) method to check if a property is enumerated. Of the examples shown in MDN, properties inherited through the prototype chain are not enumerable, so the method returns false for these properties.

Examples of non-enumerable properties are the constructors and the length property of arrays.

For the recurring part of the question, I will cite MDN: "Iterable in ECMAScript 6 is an interface (or, in other words, a protocol), and not a type of object, such as Array or Map."

That is, an object must implement this interface in order to make its properties iterable. This applies to built-in iterations such as String, Array, Map, Set, WeakSet, and Generator objects.

The following code illustrates this:

 var aString = "hello" typeof aString[Symbol.iterator] // "function" aString[Symbol.iterator]() + "" // "[object String Iterator]" [...aString] // ["h", "e", "l", "l", "o"] 

Of course, you can define your own iterator implementation.

Returning to the question, properties bound to an object or its prototype (directly, and not through inheritance) will be displayed as enumerated in a for...in loop. For iterations, you need an implementation, both mentioned earlier, and yours. Here is a great example from MDN.

 let arr = [ 3, 5, 7 ]; arr.foo = "hello"; for (let i in arr) { console.log(i); // logs "0", "1", "2", "foo" these are property names or indexes } for (let i of arr) { console.log(i); // logs "3", "5", "7" these are actual values of an // iterable implementation provided by the array prototype } 

The let keyword in this context is equivalent to the definition of var (although it has more consequences, it is beyond the scope of this post).

As you can see, the array already has an implementation of the iterable interface (from the prototype of the array), so it gives its values ​​when using the for...of loop, while the foo property is not displayed (neither the value or the name of the property).

So, if your object does not implement the iterable interface, it should not be iterable (in principle) and, thus, displays its properties in a for...of loop.

+4
source

The difference between for in and for of evaluations is that obj.[[enumerate]] , while the other uses GetIterator(obj) to determine the looped elements. [[enumerate]] does (if obj not a proxy)

returns an Iterator object, the next method iterates over all string keys of the enumerated obj properties.

GetIterator will (try) call the @@iterate method - however, regular objects do not implement this interface.

Thus, no property will be displayed in for of loops unless you explicitly specify it:

 function defineIterableProperty(obj, prop, desc) { let old = obj[Symbol.iterate]; Object.defineProperty(obj, prop, desc); obj[Symbol.iterate] = function* () { if (old) yield* old.call(this); yield prop; }; return obj; } 

(Untested, but I hope you understand this idea)

+2
source

Source: https://habr.com/ru/post/972626/


All Articles