Javascript how `length` is implemented - javascript

You know that in Javascript you can access the length of an text/array with length property:
var obj = ["Robert", "Smith", "John", "Mary", "Susan"];
// obj.length returns 5;
I want to know how this is implemented. Does Javascript calculates the length property when it is called? Or it is just a static property which is changed whenever the array is changed. My question is asked due to the following confusion in best-practices with javascript:
for(var i = 0; i < obj.length; i++)
{
}
My Problem: If it is a static property, then accessing the length property in each iteration is nothing to be concerned, but if it is calculated on each iteration, then it cost some memory.
I have read the following definition given by ECMAScript but it doesn't give any clue on how it is implemented. I'm afraid it might give a whole instance of array with the length property calculated in run-time, that if turns out to be true, then the above for() is dangerous to memory and instead the following should be used:
var count = obj.length;
for(var i = 0; i < count; i++)
{
}

Array in JavaScript is not a real Array type but it's an real Object type.
[].length is not being recalculated every time, it is being operated by ++ or -- operators.
See below example which is behaving same like array.length property.
var ArrayLike = {
length: 0,
push: function(val){
this[this.length] = val;
this.length++;
},
pop: function(){
delete this[this.length-1];
this.length--;
},
display: function(){
for(var i = 0; i < this.length; i++){
console.log(this[i]);
}
}
}
// output
ArrayLike.length // length == 0
ArrayLike.push('value1') // length == 1
ArrayLike.push('value2') // length == 2
ArrayLike.push('value3') // length == 3
ArrayLike.pop() // length == 2
ArrayLike.length === 2 // true

var a = ["abc","def"];
a["pqr"] = "hello";
What is a.length?
2
Why?
a.length is updated only when the index of the array is a numeric value. When you write
var a = ["abc","def"];
It is internally stored as:
a["0"] = "abc"
a["1"] = "def"
Note that the indexes are really keys which are strings.
Few more examples:
1.)
var a = ["abc","def"];
a["1001"] = "hello";
What is a.length?
1002
2.) Okay, let's try again:
var a = ["abc","def"];
a[1001] = "hello";
What is a.length?
1002
Note here, internally array is stored as
a["0"] = "abc"
a["1"] = "def"
a["1001"] = "hello"
3.) Okay, last one:
var a = ["abc"];
a["0"] = "hello";
What is a[0]?
"hello"
What is a.length?
1
It's good to know what a.length actually means: Well now you know: a.length is one more than the last numerical key present in the array.

I want to know how this is implemented. Does Javascript calculates the length property when it is called? Or it is just a static property which is changed whenever the array is changed.
Actually, your question cannot be answered in general because all the ECMA specs say is this:
The length property of this Array object is a data property whose
value is always numerically greater than the name of every deletable
property whose name is an array index.
In other words, the specs define the invariant condition of the length property, but not it's implementation. This means that different JavaScript engines could, in principle, implement different behavior.

Related

Hello, I keep getting undefined when I run this piece of code

this is my code:
var a = 10;
for(var i = 0; i < a; i++){ document.write(a[i]); }
I have left the var empty but it still didn't work.
a[i] looks up the property whose name is the value of i on whatever's in a. What you have in a is the primitive number 10. When you try to get an object property from a primitive number, it gets temporarily promoted to the equivalent Number instance, and then the property is taken from that instance. (Loosely speaking.)
Your i has the vaules 0 through 9, so those are the names of the properties that get looked up. Numbers don't have properties with those names, and so you get what you always get when you try to retrieve a property that doesn't exist: undefined.
You attempt to subscript an integer variable is not going to work. Try using an array instead.
var a = [item1, item2, ...];
and then use a loop to iterate over individual item and display:
for (i = 0; i < a.length; i++) {
document.write(a[i]);
}

JavaScript: How to create new object properties/members and assign values inside a For Loop?

I am trying create a function to create and assign value to an object property/member. But I'm getting the error:
Uncaught TypeError: Cannot read property 'id' of undefined
The function is suppose to create a property/member called 'id', and it is also suppose to assign a value to the newly created property/member.
var add_Ids = function(array,index) {
for(var iii = 1; iii <= 3; iii++) {
array[index+iii].id = (array[index].id * 4)+iii;
}
array[index].id *= 4;
};
array is the array that I pass into the function.
index is the position in the array to start on with the For Loop
P.S. The For Loop is not overwriting anything important.
The element that corresponds to "array[index+iii]" is empty.
array[index+iii].id = (array[index].id * 4)+iii;
In that, If array[index+iii] is undefined before, Then array[index+iii].id would give that error you've mentioned.
So before accessing id check whether the property exists.
if(!array[index+iii]) array[index+iii] = {}; // initializing if its not present.
array[index+iii].id = (array[index].id * 4)+iii;
There's a couple of things at play here.
An array element must exist before it can be manipulated. Consider this code -
var my = [];
my[0].id = 1; // TypeError: Cannot set property 'id' of undefined
This is because exactly as the error states, my[0] is undefined here. Since your array is passed into a function, do one of the following (depends upon the circumstances/requirements of this function):
Ensure that you only pass in arrays that will meet the criteria of your function. In this case, your function expects an array with 3 elements of indices [iii+index,iii+index+3].
Ensure that the count you pass in doesn't cause your operation to exceed the length of the passed in array.
Fail with a meaningful error message - test for undefined and if so, generate a meaningful error.
If this matches what you are doing, you can check for undefined and make a default option if needed.
Example of the last:
var add_ids = function(array, index) {
for (var i = 1, i <= 3; i++) {
if (!array[index + i]) {
array[index + i] = generateDefaultObject();
}
array[index + i].id = (array[index].id * 4) + i;
}
array[index].id *= 4
}
Second, it seems as though that you expect this to work. It is similar to JavaScript's implicit global declaration. For example:
my = 4; // my didn't exist before this line, but now does as a global
is (unfortunately) valid JavaScript. Arrays do not support this kind of declaration for elements - they need to exist before you work with them.

How to Call This Anonymous Javascript Function?

var avg = function()
{
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++)
{
sum += arguments[i];
}
return sum / arguments.length;
}
When I try to call this like:
var average = avg(2,3,5);
average; // It works fine;
But how do I call it without assigning to a variable?
If anybody can give any suggestion it will be delightful..Thanks.
You'd simply call it like this:
avg(2, 3, 5);
If you want to see the result, put it in an alert call:
alert( avg(2, 3, 5) );
You don't need to put the result from calling the function in a variable, you can do whatever you like with it.
For example, use it as the value in an alert:
alert(avg(2,3,5));
You can use it in another expression:
var message = "The average is " + avg(2,3,5);
You can use it directly in another call:
someFunction(avg(2,3,5));
You can even throw the result away by not doing anything with it, even if that's not useful in this specific situation:
avg(2,3,5);
If you don't put the result into a variable or in a compatible context, this function cannot output anything, which makes it difficult to use unless you make it output the result. Try this :
var avg = function()
{
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++)
{
sum += arguments[i];
}
var retvalue = sum / arguments.length;
consoloe.log("avg: "+retvalue);
return retvalue ;
}
Then it may help you to see whenever the function is called or not.
You need to understand the concept of expressions.
Every expression as a whole represents one value. An expression can be made up of multiple subexpressions that are combined in some manner (for example with operators) to yield a new value.
For instance:
3 is an expression (a literal, to be specific) that denotes the numeric value three.
3 + 4 is an expression, made up of two literal expressions, that as a whole yields the value 7
When you assign a value to a variable – as in var average = – the right hand side of the =-operator needs to be an expression, i.e. something that yields a value.
As you have observed, average will have been assigned the value five. It thus follows, that avg(2, 3, 5) must itself be an expression that evaluated to the value 5.
average itself is an expression, denoting the current value of said variable.
The most important thing to take away from this is, that avg() is in no way connected to var average =. avg() stands on its own, you can just think it like an ordinary value such as 5 (there are other differences of course).
If you have understood the concept of expressions and values, it should be clear that if you can do
var average = avg(2,3,5);
average; // It works fine;
You can also do
avg(2,3,5);

Javascript: sort multidimensional array

After creating a multi-dim array like this, how do I sort it?
Assuming 'markers' is already defined:
var location = [];
for (var i = 0; i < markers.length; i++) {
location[i] = {};
location[i]["distance"] = "5";
location[i]["name"] = "foo";
location[i]["detail"] = "something";
}
For the above example, I need to sort it by 'distance'.
I've seen other questions on sorting arrays and multi-dim arrays, but none seem to work for this.
location.sort(function(a,b) {
// assuming distance is always a valid integer
return parseInt(a.distance,10) - parseInt(b.distance,10);
});
javascript's array.sort method has an optional parameter, which is a function reference for a custom compare. the return values are >0 meaning b first, 0 meaning a and b are equal, and <0 meaning a first.
Have you tried this?
location.sort(function(a,b) {
return a.distance - b.distance;
});
Both sort functions posted so far should work, but your main problem is going to be using location as a variable as it is already system defined.

javascript: speedy Array.contains(otherArray)?

I have an array of arrays. The inner array is 16 slots, each with a number, 0..15. A simple permutation.
I want to check if any of the arrays contained in the outer array, have the same values as
a test array (a permutation of 16 values).
I can do this easily by something like so:
var containsArray = function (outer, inner) {
var len = inner.length;
for (var i=0; i<outer.length; i++) {
var n = outer[i];
var equal = true;
for (var x=0; x<len; x++) {
if (n[x] != inner[x]) {
equal = false;
break;
}
}
if (equal) return true;
}
return false;
}
But is there a faster way?
Can I assign each permutation an integral value - actually a 64-bit integer?
Each value in a slot is 0..15, meaning it can be represented in 4 bits. There are 16 slots, which implies 64 total bits of information.
In C# it would be easy to compute and store a hash of the inner array (or permutation) using this approach, using the Int64 type. Does Javascript have 64-bit integer math that will make this fast?
That's just about as fast as it gets, comparing arrays in javascript (as in other languages) is quite painful. I assume you can't get any speed benefits from comparing the lengths before doing the inner loop, as your arrays are of fixed size?
Only "optimizations" I can think of is simplifying the syntax, but it won't give you any speed benefits. You are already doing all you can by returning as early as possible.
Your suggestion of using 64-bit integers sounds interesting, but as javascript doesn't have a Int64 type (to my knowledge), that would require something more complicated and might actually be slower in actual use than your current method.
how about comparing the string values of myInnerArray.join('##') == myCompareArray.join('##'); (of course the latter join should be done once and stored in a variable, not for every iteration like that).
I don't know what the actual performance differences would be, but the code would be more terse. If you're doing the comparisons a lot of times, you could have these values saved away someplace, and the comparisons would probably be quicker at least the second time round.
The obvious problem here is that the comparison is prone to false positives, consider
var array1 = ["a", "b"];
var array2 = ["a##b"];
But if you can rely on your data well enough you might be able to disregard from that? Otherwise, if you always compare the join result and the lengths, this would not be an issue.
Are you really looking for a particular array instance within the outer array? That is, if inner is a match, would it share the same reference as the matched nested array? If so, you can skip the inner comparison loop, and simply do this:
var containsArray = function (outer, inner) {
var len = inner.length;
for (var i=0; i<outer.length; i++) {
if (outer[i] === inner) return true;
}
return false;
}
If you can't do this, you can still make some headway by not referencing the .length field on every loop iteration -- it's an expensive reference, because the length is recalculated each time it's referenced.
var containsArray = function (outer, inner) {
var innerLen = inner.length, outerLen = outer.length;
for (var i=0; i<outerLen; i++) {
var n = outer[i];
var equal = true;
for (var x=0; x<innerLen; x++) {
if (n[x] != inner[x]) {
equal = false;
}
}
if (equal) return true;
}
return false;
}
Also, I've seen claims that loops of this form are faster, though I haven't seen cases where it makes a measurable difference:
var i = 0;
while (i++ < outerLen) {
//...
}
EDIT: No, don't remove the equal variable; that was a bad idea on my part.
the only idea that comes to me is to push the loop into the implementation and trade some memory for (speculated, you'd have to test the assumption) speed gain, which also relies on non-portable Array.prototype.{toSource,map}:
var to_str = function (a) {
a.sort();
return a.toSource();
}
var containsString = function (outer, inner) {
var len = outer.length;
for (var i=0; i<len; ++i) {
if (outer[i] == inner)
return true;
}
return false;
}
var found = containsString(
outer.map(to_str)
, to_str(inner)
);
var containsArray = function (outer, inner) {
var innerLen = inner.length,
innerLast = inner.length-1,
outerLen = outer.length;
outerLoop: for (var i=0; i<outerLen; i++) {
var n = outer[i];
for (var x = 0; x < innerLen; x++) {
if (n[x] != inner[x]) {
continue outerLoop;
}
if (x == innerLast) return true;
}
}
return false;
}
Knuth–Morris–Pratt algorithm
Rumtime: O(n), n = size of the haystack
http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm

Categories