I'm a bit confused by the Array.length property (i.e. a property named length on the Array function object) and array_instance.length (i.e. a property named length on instance of array object)
So what is difference between the two length property and when should/shouldn't we use them?
Edit 1:
there is also a length property on Array.prototype object. I am so confused.
Edit 2
Just to paint a clearer picture, here are the different length properties I have found
Edit 3
This is one of the follow up questions I asked in the comment section, but I think the question is important to fully understanding length property, so I have copy-pasted here in the main section
Follow up question:
Array.prototype.hasOwnProperty('length') and Array_instance.hasOwnProperty('length') return true, does that mean there are two length properties, one on array_instance, one on Array.prototype object, with the array_instance.length overshadowning the Array.prototype.length?
functions have a .length property which corresponds to how many arguments they are expecting. For example:
const unary = (a) => {
}
const binary = (a, b) => {
}
console.log(unary.length);
console.log(binary.length);
So the Array constructor has a length of 1 because it expects one parameter to be passed to it (namely, the size of the array).
array objects also have a .lengthproperty, which is unrelated other than having the same name. This property says how large the array currently is.
I really think a lot of the other answers have covered everything needed here, but as it seems the OP hasn't had what they see a a clear answer, I will try to set everything out, somewhat extensively - but as clearly as I can - in order to clarify. (Apologies if anyone thinks I am "stealing" their answer - I assure you that this is not the intention, and I'm deliberately not looking at them as I type this, but I've certainly read most of them and even upvoted a few.)
Array.length
This has already been well-covered above. Array is a native JS function, which you can use for creating arrays. It's less common then simply defining an array literal (and as far as I know there is no reason it would ever be preferable), but instead of var a = [1,2,3] you are allowed to do this:
var a = Array(1,2,3);
console.log(a);
Note in passing that you don't want to do this to create a singleton array, there is an utterly mad gotcha of a special case when you supply exactly one parameter which happens to be an integer:
var a = Array(5);
console.log(a);
Although that shows what appears to be an array of 5 undefined values in whatever JS console implementation SO uses, that's not actually quite what has been created (nor what is displayed in the current version of Chrome). I'm getting way off-topic but I'll refer you to Kyle Simpson's excellent walkthrough of the madness.
Anyway, since Array is a function, as others have already observed, it has a length property as all functions do. I'm really not sure why it evaluates to 1 though - for a user-defined function it is the number of arguments the function was formally declared with, but since Array like all native JS functions isn't actually implemented in JS, I couldn't tell you how the implementation actually works. Clearly it can take any number of arguments and thus is a rather "exotic" function. I don't think that Array.length would ever be useful, no matter what value was arbitrarily assigned to it, but it seems that most implementations go for 1, even if the specification leaves it open. (I'm not enough of a spec devotee to know if this is actually defined in there or left up to implementations.)
arrayinstance.length
This is just the feature of arrays that we know and use all the time. All JS arrays get this property - note that, although it is a property rather than a method (that is, it is not a function), it nevertheless "auto-updates" as the array gets longer/shorter:
var a = [1,2,3];
console.log(a.length);
a.push(4);
console.log(a.length);
a.pop();
a.pop();
console.log(a);
console.log(a.length);
Although as I said, Javascript's native constructors are not implemented in terms of JS itself, you could implement this kind of behaviour by defining a getter (at least since ES5).
Array.prototype.length
To fully explain what Array.prototype (and similar objects) is would take me deep into how Javascript's object system work. Suffice to say here that, unlike class-based languages (and JS does not have classes, even in ES6, despite the class syntax allowing us often to pretend it does), JS does not have the usual concept of "inheritance" that so-called OO languages do. In JS's version (sometimes called "prototypal inheritance"), what happens it that each object has an "internal prototype" which references some other object - and if you try to access a property on that object which it doesn't have, the JS engine will look at that "prototype object" for the property and use its value instead.
It's actually a very simple mechanism, but there are a number of things in the language which confuse this, one of them being the fact that functions (which are also objects) have a property called prototype - which does not point to the real "prototype" object which gets consulted if a nonexistent property is referenced on the function object. (A normal function foo has Function.prototype is the object that it delegates to - not foo.prototype.) However, if you declare a function foo, an object called foo.prototype is created - which is basically an empty, nondescript object. Its significance is that if the function foo is used as a "constructor" - that is, if you make an object by calling new foo() - foo.prototype will then be the object that JS will look up properties (including methods) on if any object constructed from foo happens to fail a property lookup.
This is why, at least in pre-ES6 code, you quite frequently saw this kind of pattern:
function foo(a,b) {
this.a = a;
this.b = b;
}
foo.prototype.add = function() {
this.a = this.a + this.b;
}
var myFoo = new foo(1,2);
console.log(myFoo.a);
myFoo.add();
console.log(myFoo.a);
myFoo.add();
console.log(myFoo.a);
console.log(myFoo.hasOwnProperty("add"));
Despite appearances, myFoo doesn't actually have a method add in this example - as confirmed by the final console.log. When the JS engine fails to find the property though, it goes to myFoo's "internal prototype", which happens to be foo.prototype. And that's why the method works, as it would on any object constructed from foo.
Anyway, this is leading up to the fact that Arrays, which could be (although almost never are) constructed by calling new Array (I didn't use the new operator above, but I could have done, this is a case where it makes no difference), therefore delegate to Array.prototype. All those array methods that you know and love don't "really" exist on the arrays you call them on:
var a = [1,2,3];
a.push(4);
console.log(a);
console.log(a.hasOwnProperty("push"));
console.log(Array.prototype.hasOwnProperty("push"));
So array methods only work because those methods are actually found on the Array.prototype object, to which all arrays delegate for property/method access if the lookup doesn't succeed on the array itself. (And this is why, if you look up any of them on MDN, the top of the page always says Array.prototype.<method_name>, because that's where the method "really" lives.)
A drastic demonstration of this (please DON'T do this in production code!)
// you're used to doing this, and it works:
[1,2].push(3);
console.log("that went fine");
// vandalism on a grand scale!
Array.prototype.push = undefined;
// now you can'tse the "push" method anymore!
[1,2,3].push(4);
But I'm going to end on something of an anticlimax. The above is true for array methods - but the length array property isn't a method. As observed above, it's just a "plain" (non-function) property, which "magically" behaves somewhat like a function call. As observed in the OP, .length property accesses don't delegate as the method calls shown above do, the property exists on each array in itself.
So why does Array.prototype still itself have a length property? Well, Array.prototype is actually itself an array. In fact, that's not the only thing:
Array.prototype.push(1);
console.log(Array.prototype);
Function.prototype();
notice that Array.prototype.push(1) ends up with Array.prototype being the singleton array [1]. So Array.prototype is "kind of like" the empty array (it's not exactly the same, because it has all those methods mentioned above directly accessible on the object itself, which a "normal" empty array doesn't). And with Function.prototype, although calling it didn't output anything, the fact that no TypeError was raised proves that it really is a function (it's actually a "no-op" function, like function() {}, but once again with various methods diretcly on it - the methods which every function has access to, such as .call and .bind).
Anyway, to cut the digression short, since Array.prototype is - as far as ordinary array properties are concerned, at least - an empty array, this explains why it has a length property, and why it's equal to 0.
I hope this clears things up, as well as demonstrating some of the more intriguing parts of Javascript.
The first part has already been answered, Array constructor is a function and functions have a .length property.
For the second, Array.prototype.length, it's a bit more obscur...
Array.prototype is actually an Array:
console.log(Array.isArray(Array.prototype)); // true
Array.prototype.push('hello');
console.log(Array.prototype.length); // 1
console.log(Array.prototype[0]); // "hello"
As to why is it an Array? Because specs say so:
The Array prototype object is an Array exotic objects and has the internal methods specified for such objects. It has a length property whose initial value is 0 and whose attributes are { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }..
There is also a note specifying that it is for compatibility reasons with previous versions of the specs.
As to why is was designed as being an Array? I have no really strong idea...
Disclaimer:
I have tried to show how constructor and instance works in general. But in fact, they have huge difference between different constructors.
Any constructor has been set its length with the value specified by the spec. Specially most of them are set to 1:
Number.length // 1
Object.length // 1
Function.length // 1
Array.length // 1
// etc.
Similarly,
Array.constructor.length // 1
// etc.
Like #Kaiido pointed out in the comment, you can see some constructor length is set:
Document.length // 0
Int8Array.length // 3
Date.length // 7
And you may also notice the length of the instance is undefined as they are not set. - It's out of the scope though.
let d = new Date
d.length === undefined // true
See at the bottom for relevant references.
But when you have an instance of it, then you're creating a new value of it:
typeof new Array === typeof Array.prototype // true
typeof new Function === typeof Function.prototype // true
// etc.
So, when you use an instance it has no length value set because it has no any parameters:
let arr = new Array // Array.prototype
arr.length === 0 // true
But when you use an instance with parameter, then you have the length property with the value of parameters
let arr = new Array(20)
arr.length === 20 // true
let func = function(a1,a2,a3,a4){}
func.length === 4 // true
// etc.
So now, you have been wondering why the constructor has length value equal to 1?
It's because the spec has set the value to be 1 initially.
Every built-in Function object, including constructors, has a length property whose value is an integer. Unless otherwise specified, this value is equal to the largest number of named arguments shown in the subclause headings for the function description, including optional parameters.
The value of the [[Prototype]] internal slot of the Object constructor is the intrinsic object %FunctionPrototype%.
Besides the length property (whose value is 1),
See these references:
Standard built in objects,
19.1.2 Properties of the Object Constructor,
19.2.2 Properties of the Function Constructor,
etc.
Also, you can see the prototype has length to 0, you already know it why in the preceding example.
Though, here's just a reference stating that:
19.2.3 Properties of the Function Prototype Object
And there some constructor whose length is set different. This is the out of scope of this answer. Though, here's a reference for the date constructor:
20.3.3 Properties of the Date Constructor
So, it's totally up to the spec how they have been defined.
Array.length
Array is constructor which means its type is "function". You try the checking it console.
typeof Array //"function"
According to MDN
The length property indicates the number of parameters expected by the function.
As the Array function expects single argument so Array.length = 0
array_instance.length
The length property of an object which is an instance of type Array sets or returns the number of elements in that array
As we know that arrays are actually objects so objects can have properties. The property length is on the instance of array.
Now second question you may ask why we don't get the length properties of array using Object.keys or for..in loop. The answer is because this property is not Enumerable.
let arr= [];
//this.property 'length2' will not be shown in for..in or Object.keys();
Object.defineProperty(arr,'length2',{
value:'length2 for test',
enumerable:false
})
//this property 'x' will be displayed in for..in loop and Object.keys()
Object.defineProperty(arr,'x',{
value:'length2 for test',
enumerable:true
})
console.log(Object.keys(arr)); //["x"]
Array.prototpe.length
According to the DOCS
The initial value of Array.prototype.constructor is the standard built-in Array
The Array prototype object is itself an array; its [[Class]] is "Array", and it has a length property (whose initial value is +0) constructor
Actually Array.prototype is an array. And remember array is always object. So it can have properties. The methods of the Array are stored in form of key:value. and there is no element in that array so it Array.prototype.length returns 0. If you push() some elements into it you will see it as array.
console.log(Array.prototype.length) //0
console.log(Array.isArray(Array.prototype)) //true
//adding element to array
Array.prototype.push('x')
console.log(Array.prototype.length) //1
As I explained in second parts you can hide properties of Object by setting enumerable:false. All the methods are keys of Array.prototype But now shown in for..in loops.
Array.length
For the number of properties in the array or the length property of an object which is an instance of type Array sets or returns the number of elements in that array.
Array.prototype.length
Inherited number of properties in the array. When you check Array.length you're actually checking Array.prototype.length
Suddenly, I am seeing a strange behavior.
Here is a snippet:
// attributesList is an object with properties 0, 1, 2.
for (var j in attributesList) {
// this loop should run 3 times.
var attribute = attributesList[j];
}
As you can see from above, the loop should run 3 times. But for some very strange reason it is being run 4 times. For the last iteration the value of j == "seek".
Even stranger, this same code base works on another git branch (no changes). This only seems to happen when I run this from a particular git branch.
Is there any logical explanation for this mysterious "seek" property?
One thing I tried looking into is perhaps javascript version and any other versioning differences... but no luck here.
* Updated *
attributesList is an array of object type.
The object in question has four enumerable properties. It probably inherits seek from its prototype object, which is why you think it only has three properties.
Your comment to MikeC adds weight to that:
when I evaluate the attributesList during run/debug time I do not see any property called "seek"
As does your update:
attributesList is an array of object type.
That tells us that somewhere in your codebase (probably in a plugin), someone has been very naughty and added an enumerable property to Array.prototype. They can do that with various different syntaxes; if it's just the one property (seek), it's probably like this:
Array.prototype.seek = function() {
// ...
};
That's poor practice, they should have made it non-enumerable:
Object.defineProperty(Array.prototype, "seek", {
value: function() {
// ...
}
});
But fundamentally, for-in is not for looping through arrays. See my other answer here for how to loop through arrays.
Two excerpts from that long answer:
Use forEach:
attributesList.forEach(function(attribute) {
// ...
});
or if you really want to use for-in, add a hasOwnProperty check:
for (var j in attributesList) {
if (attributesList.hasOwnProperty(j)) {
// this loop should run 3 times.
var attribute = attributesList[j];
}
}
or of course use a for loop. See the answer for details.
We are supposed to use hasOwnProperty() when iterating over the keys of an object because Object.prototype may be polluted, which through prototype inheritance, will also pollute the keys of all objects.
So if I don't pollute Object.prototype, I should be able to skip hasOwnProperty() which slows down the for-in loops. It will also make the code simpler.
Idea: first check that Object.prototype is not polluted, then don't use hasOwnProperty().
Checking that Object.prototype was not polluted is done by the following function. I will call this in a strategic place in my code which is executed occasionally during the script execution (like before I am going to process a bunch of datas). This function is merely a guard alerting me if anything bad was done to Object.prototype:
/* jshint -W089 */ // http://jslinterrors.com/the-body-of-a-for-in-should-be-wrapped-in-an-if-statement/
var checkObjectPrototypeNotAugmented = function() {
/* jshint unused:false */ // Because key is considered unused
// Check if there is any enumerable property on Object.prototype:
for(var key in Object.prototype) {
throw new Error("Object.prototype has been augmented with keys: " + Object.prototype.keys());
}
};
Note: I put the /* jshint -W089 */ comment so that jshint wont complain about missing hasOwnProperty().
Question: Is this ok ? Is there anything else I should be careful about ? Or that I can improve ?
Now some benchmarks:
Here are 3 jsPerf benchmarks which show the gains for objects with different numbers of properties:
1 property: Iterate own keys of plain objects with 1 property
10 properties: Iterate own keys of plain objects with 10 properties
100 properties: Iterate own keys of plain objects with 100 properties
Note: the Object.prototype check is executed each time the properties of an object are going to be iterated. In a real situation, the test needs only to be performed once: when the full page is loaded (and then from time to time to be sure that no script inadvertently modified Object.prototype). So in real situation, you would get the performance of the "Reference" test. But this shows that even when always performing the test, it stays faster.
Interesting results:
not using hasOwnProperty() either gives the same speed or is faster depending on the browser
even when accessing only 1 property, checking Object.protoype before each for-in loop can be faster in some browser than hasOwnProperty() ! (But I don't recommend always checking Object.prototype like this)
Related: we see also that using Object.keys() can be even faster in some browsers for large objects, but it can also be slower for small objects. But using Object.keys() forces you to either only support browsers >= IE 9, or to augment the Object.prototype with a polyfill in IE <= 8. So for old browser compatibility, you would have to choose either Object.keys() or checkObjectPrototypeNotAugmented().
(Let us suppose that there is a good reason for wishing this. See the end of the question if you want to read the good reason.)
I would like to obtain the same result as a for in loop, but without using that language construct. By result I mean only an array of the property names (I don't need to reproduce the behavior that would happen if I modify the object while iterating over it).
To put the question into code, I'd like to implement this function without for in:
function getPropertiesOf(obj) {
var props = [];
for (var prop in obj)
props.push(prop);
return props;
}
From my understanding of the ECMAScript 5.1 specification about the for in statement and the Object.keys method, it seems the following implementation should be correct:
function getPropertiesOf(obj) {
var props = [];
var alreadySeen = {};
// Handle primitive types
if (obj === null || obj === undefined)
return props;
obj = Object(obj);
// For each object in the prototype chain:
while (obj !== null) {
// Add own enumerable properties that have not been seen yet
var enumProps = Object.keys(obj);
for (var i = 0; i < enumProps.length; i++) {
var prop = enumProps[i];
if (!alreadySeen[prop])
props.push(prop);
}
// Add all own properties (including non-enumerable ones)
// in the alreadySeen set.
var allProps = Object.getOwnPropertyNames(obj);
for (var i = 0; i < allProps.length; i++)
alreadySeen[allProps[i]] = true;
// Continue with the object's prototype
obj = Object.getPrototypeOf(obj);
}
return props;
}
The idea is to walk explicitly the prototype chain, and use Object.keys to get the own properties in each object of the chain. We exclude property names already seen in previous objects in the chain, including when they were seen as non-enumerable. This method should even respect the additional guarantee mentioned on MDN:
The Object.keys() method returns an array of a given object's own
enumerable properties, in the same order as that provided by a
for...in loop [...].
(emphasis is mine)
I played a bit with this implementation, and I haven't been able to break it.
So the question:
Is my analysis correct? Or am I overlooking a detail of the spec that would make this implementation incorrect?
Do you know another way to do this, that would match the implementation's specific order of for in in all cases?
Remarks:
I don't care about ECMAScript < 5.1.
I don't care about performance (it can be disastrous).
Edit: to satisfy #lexicore's curiosity (but not really part of the question), the good reason is the following. I develop a compiler to JavaScript (from Scala), and the for in language construct is not part of the things I want to support directly in the intermediate representation of my compiler. Instead, I have a "built-in" function getPropertiesOf which is basically what I show as first example. I'm trying to get rid of as many builtins as possible by replacing them by "user-space" implementations (written in Scala). For performance, I still have an optimizer that sometimes "intrinsifies" some methods, and in this case it would intrinsify getPropertiesOf with the efficient first implementation. But to make the intermediate representation sound, and work when the optimizer is disabled, I need a true implementation of the feature, no matter the performance cost, as long as it's correct. And in this case I cannot use for in, since my IR cannot represent that construct (but I can call arbitrary JavaScript functions on any objects, e.g., Object.keys).
From the specification point of view, your analysis correct only under assumption that a particular implementation defines a specific order of enumeration for the for-in statement:
If an implementation defines a specific order of enumeration for the
for-in statement, that same enumeration order must be used in step 5
of this algorithm.
See the last sentence here.
So if an implementation does not provide such specific order, then for-in and Object.keys may return different things. Well, in this case even two different for-ins may return different things.
Quite interesting, the whole story reduces to the question if two for-ins will give the same results if the object was not changed. Because, if it is not the case, then how could you test "the same" anyway?
In practice, this will most probably be true, but I could also easily imagine that an object could rebuild its internal structure dynamically, between for-in calls. For instance, if certain property is accessed very often, the implementation may restructure the hash table so that access to that property is more efficient. As far as I can see, the specification does not prohibit that. And it is also not-so-unreasonable.
So the answer to your question is: no, there is no guarantee according to the specification, but still will probably work in practice.
Update
I think there's another problem. Where is it defined, what the order of properties between the members of the prototype chain is? You may get the "own" properties in the right order, but are they merged exactly the way as you do it? For instance, why child properties first and parent's next?
I'm currently use jquery 1.8.3. I think it added indexOf to Array.prototype so now every of my array always contains the method indexOf as the first element.
Doing for (var i in object) I always get the method infexOf as my first element and it bugged my code.
Bug happened on IE8 only.
What I want is to remove this indexOf from all arrays or anyway to hack jquery / resolve this problem.
PS: I'm not even sure if it's jquery is the cause of this problem
Thanks.
Aside from not using for...in to iterate over an array, if you must use for...in, then combine it with hasOwnProperty to tell if the property you are looking at really belongs to the object in question, or came from the prototype:
for (var prop in myObject) {
if (myObject.hasOwnProperty(prop)) {
// this didn't come from the prototype.
}
}
The correct answer here is that you shouldn't be using a for(...in...) loop to iterate an Array in Javascript.
The whole point of having an Array is that it has a numbered sequence of elements, so you should be using a for() loop.
for(var i=0; i<myArray.length; i++) {
//do stuff here with myArray[i]
}
That alone will resolve the issue in this case, because it will only iterate the numbered elements, so the indexOf method won't get involved.
However, a brief explaination of the problem with for(..in..) here may be helpful, so let me explain...
The underlying cause of the error you're seeing is because the indexOf method isn't supported for arrays in IE8, so something in your code (not jQuery though) has added it to the Array prototype.
This in turn means that when you do a for(..in..) loop, it will be picked up as one of the elements to be iterated.
In this case, you have a better solution (the for() loop; see above), but in cases where you really do need to use a for(..in..) loop, this can be a real problem. You can prevent this by checking hasOwnProperty() immediately inside your for(..in..) loop. This function returns false for items that are part of the object prototype, so it helps you avoid hitting unwanted methods when looping an object.
This is considered best practice for every for(..in..) loop. In fact, if you use a tool like JSLint, to check your coding style, it will complain if you don't do this.