What does enumerable mean?
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
What are the benefits of making properties non-enumerable?
I think the main benefit is to be able to control what shows up when enumerating an object's properties, such as for in
or Object.keys()
.
MDN explains it well with Object.defineProperty
: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty
So normally, when people want to add a method to Object
, such as a polyfill for some method not supported in old browsers, they modify the .prototype
. But that makes the property enumerable and messes up what is returned in loops/keys collection (without using .hasOwnProperty
...which not everyone uses).
So instead of something like:
Object.prototype.myMethod = function () {
alert("Ahh");
};
you could use Object.defineProperty
to explicitly say to have it not be enumerable:
Object.defineProperty(Object.prototype, 'myMethod', {
value: function () {
alert("Ahh");
},
enumerable: false
});
That way, for example when you use for (var key in obj)
, "myMethod" won't be an item enumerated, and you won't have to worry about using .hasOwnProperty
. The main problem with this is that some browsers don't support it of course: http://kangax.github.com/es5-compat-table/ and that not all libraries/code use it, so you can't always rely on external libraries/code to do use correctly and all the time.
You can access a non-enumerable property at any time you want, it just won't show up when enumerating the object's properties - that's the main point.
And I do believe that all "predefined" properties of objects are non-enumerable. By that, I really only mean native properties, not necessarily inherited or created. So with your example, pop
and push
will not be enumerated over, but Array.prototype.indexOf
will be if it is created as a polyfill on an old browser that doesn't support that method...which of course, can be avoided by using Object.defineProperty
like my example above. Another example is the length
property, which is not enumerated over.
Here's an example in general: http://jsfiddle.net/aHJ3g/
The use and definition of Object.keys
is important: "Returns an array of a given object's own enumerable properties, in the same order as that provided by a for-in
loop (the difference being that a for-in
loop enumerates properties in the prototype chain as well)." - from MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
In Ruby, what does it mean to return an 'enumerable'
An Enumerator abstracts the idea of enumeration so that you can use all of the handy Enumerable
methods without caring what the underlying data structure is.
For example, you can use an enumerator to make an object that acts kind of like an infinite array:
squares = Enumerator.new do |yielder|
x = 1
loop do
yielder << x ** 2
x += 1
end
end
squares.take(10)
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
squares.count
# don't wait up for this one!
The cool thing about enumerators is that they are enumerable themselves and most Enumerable
methods return enumerators if you don't give them a block. This is what allows you to chain method calls to get one big enumerator.
Here's how I would code each_with_index
so that it can be chained nicely:
class Array
def my_each_with_index &blk
e = Enumerator.new do |yielder|
i = 0
each do |x|
yielder << [x, i]
i += 1
end
end
return e unless blk
e.each(&blk)
end
end
[3,2,1].my_each_with_index { |x, i| puts "#{i}: #{x}" }
# 0: 3
# 1: 2
# 3: 1
So first we create an enumerator which describes how to enumerate with indices. If no block is given, we simply return the enumerator. Otherwise we tell the enumerator to enumerate (which is what each
does) using the block.
Is there any difference between enumerable and own properties?
Enumerabilty and ownership of properties are orthogonal to each other. There are enumerable own properties, non-enumerable own properties, enumerable inherited properties and non-enumerable inherited properties.
The "and" in the MDN quote signifies that a property must both be owned and be enumerable to be copied by Object.assign
- in short, it copies own enumerable properties.
Can anyone explain IEnumerable and IEnumerator to me?
for example, when to use it over foreach?
You don't use IEnumerable
"over" foreach
. Implementing IEnumerable
makes using foreach
possible.
When you write code like:
foreach (Foo bar in baz)
{
...
}
it's functionally equivalent to writing:
IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
bar = (Foo)bat.Current
...
}
By "functionally equivalent," I mean that's actually what the compiler turns the code into. You can't use foreach
on baz
in this example unless baz
implements IEnumerable
.
IEnumerable
means that baz
implements the method
IEnumerator GetEnumerator()
The IEnumerator
object that this method returns must implement the methods
bool MoveNext()
and
Object Current()
The first method advances to the next object in the IEnumerable
object that created the enumerator, returning false
if it's done, and the second returns the current object.
Anything in .Net that you can iterate over implements IEnumerable
. If you're building your own class, and it doesn't already inherit from a class that implements IEnumerable
, you can make your class usable in foreach
statements by implementing IEnumerable
(and by creating an enumerator class that its new GetEnumerator
method will return).
Related Topics
Why Isn't [1,2,3] Equal to Itself in JavaScript
Google Maps Move Marker with Lat/Lng from Ajax Success Returned Data
Can't Trigger Click with Jquery in a Chrome Extension
Jquery, Find Div Class Name at a Certain Position While Scrolling
Remembering State Before App Goes in Foreground
JSON Left Out Infinity and Nan; JSON Status in Ecmascript
Differencebetween Document and Document in JavaScript
Difference Between Dot Notation and Bracket Notation in JavaScript
What Is Property in Hasownproperty in JavaScript
Is There a Downside to Using Es6 Template Literals Syntax Without a Templated Expression
Get Content of a Div Using JavaScript
$.Each() VS For() Loop - and Performance
No Semicolon Before [] Is Causing Error in JavaScript
Why JavaScript Function Declaration (And Expression)
Get Element's CSS Selector (When It Doesn't Have an Id)
Does JavaScript Process Using an Elastic Racetrack Algorithm