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
I read that we should always use hasOwnProperty when looping an object, because the object can be modified by something else to include some keys we don't want.
But is this always required? Are there situations where it's not needed? Is this required for local variables too?
function my(){
var obj = { ... };
for(var key in obj){
if(obj.hasOwnProperty(key)){
safe
}
}
}
I just don't like adding an extra if inside the loop if I don't have to.
Death to hasOwnProperty
This guy says I shouldn't use it at all any more.
Object.hasOwnProperty determines if the whole property is defined in the object itself or in the prototype chain.
In other words: do the so-called check if you want properties (either with data or functions) coming from no other place than the object itself.
For example:
function A() {
this.x = "I'm an own property";
}
A.prototype.y = "I'm not an own property";
var instance = new A();
var xIsOwnProperty = instance.hasOwnProperty("x"); // true
var yIsOwnProperty = instance.hasOwnProperty("y"); // false
Do you want to avoid the whole check if you want own properties only?
Since ECMAScript 5.x, Object has a new function Object.keys which returns an array of strings where its items are the own properties from a given object:
var instance = new A();
// This won't contain "y" since it's in the prototype, so
// it's not an "own object property"
var ownPropertyNames = Object.keys(instance);
Also, since ECMAScript 5.x, Array.prototype has Array.prototype.forEach which let’s perform a for-each loop fluently:
Object.keys(instance).forEach(function(ownPropertyName) {
// This function will be called for each found "own property", and
// you don't need to do the instance.hasOwnProperty check any more
});
When you're using for (var key in obj) it will loop through the given object + its parent objects' properties on the prototype chain until it reaches the end of the chain. As you want to check only a specific object's properties, you need to use hasOwnProperty.
This is not needed in for (var i = 0; i < length; i++) or data.forEach().
YES, use it always with for ... in
There are some nice answers here describing what hasOwnProperty() does and offering other solutions.
But none do provide an answer to what this question and #João in comments asks.
Is this always required?
In other words,
if the object is mine, if I have control over it, if the object is defined as my own local variable,
do I still need to use hasOwnProperty()?
The complication with this question is, that the control over the variable of Object type is not what's important in this consideration.
What's important is the control over the Object type itself.
If the question is slightly rephrased to: "Is the use of hasOwnProperty() required if I have full control over the JS script, where it's used and everything in its or parent scopes?"
Then no, you don't need to use the hasOwnProperty().
But the full control over the environment is not something you should count on.
Consider this example
var variableCreatedByInocentUser = { amisane: 'yes' };
for (let key in variableCreatedByInocentUser) {
console.log(key +'? '+ variableCreatedByInocentUser[key]);
}
console.log('-----');
Object.prototype.amicrazy = 'yes, you redefined Object type';
for (let key in variableCreatedByInocentUser) {
console.log(key +'? '+ variableCreatedByInocentUser[key]);
}
console.log('-----');
for (let key in variableCreatedByInocentUser) {
if (!variableCreatedByInocentUser.hasOwnProperty(key)) { continue; }
console.log(key +'? '+ variableCreatedByInocentUser[key]);
}
It's fine to drop the hasOwnProperty() only until someone somewhere redefines the Object type.
Before or even after your script is started.
The effect is retroactive. Even if you declared your variable "using original Object type",
it does not work as expected in JS and the redefined Object type will also affect such variables created before.
Even though the redefining of base types is discouraged, it's being done in some frameworks.
Such framework could be included and introduced into your global scope and break your script.
There might also be a safety issue. The Object could be redefined with malicious intention, making your loops perform additional tasks.
If you want to follow good practices, you should always consider all possible scenarios, like that the code you're writing could be reused or inserted, or joined with another project.
Use hasOwnProperty() even when it might seem not necessary and wasteful.
hasOwnProperty expects the property name as a string.
When you call Test.hasOwnProperty(name) you are passing it the value of the name variable (which doesn't exist), just as it would if you wrote alert(name).
Every object descended from Object inherits the hasOwnProperty method. This method can be used to determine whether an object has the specified property as a direct property of that object;
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.
(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 trying to use the 'arguments' variable available to a function in order to enumerate the arguments passed to a function, in Javascript, using :
for (var i in arguments){
...
}
This seems to be working for me in the chrome and firebug consoles, while does not work with Rhino. With the former two, I can successfully enter the for loop and see the arguments, while with the latter, it doesn't seem like the for loop is even entered.
Why is this happening and how can I prevent this ?
From Javascript for..in looping over arguments ie.for( arg in arguments) does not work in IE8 but it works in Chrome 8 :
First of all, while the arguments object available within a function is not an array, it is "array-like" enough such that an incremental for loop (for (var i = 0, len = arguments.length; i < len; i++) { ... }) is preferable - not only because it runs faster, but also because it avoids other pitfalls - one of which is exactly what you're falling into.
To actually answer the question of why the second loop doesn't work, it's important to realize just what for ... in loop does: it iterates through all enumerable properties found in an object. Now, I've bolded 2 words in that statement, because I used these two words purposefully to indicate a couple of nuances that, while they may seem subtle, can drastically affect the behavior of your code if you don't realize what's going on.
First let's focus on all - by which I mean to say, not just properties of the object itself, but also potentially properties said object has inherited from its prototype, or its prototype's prototype, or so on. For this reason, it is very often recommended that you "guard" any for ... in loop by immediately additionally qualifying it with the condition if (obj.hasOwnProperty(p)) (assuming your loop were written for (var p in obj)).
But that's not what you're running into here. For that, let's focus on that second word, enumerable. All properties of objects in JavaScript are either enumerable or non-enumerable, which pretty much directly relates to whether the property shows up in a for ... in loop or not. In browsers such as Firefox and IE, as it turns out, the arguments object's numeric properties are not enumerable (nor is its length as it were), which is precisely why you're not iterating through anything!