Javascript Garbage Collection on a Returned Array - javascript

I'm sure that this is an easy question for JS experts out there. Unfortunately for me I'm not one of them.
I've got the following situation. I'm creating an array in function b that I populate with some new objects. I then return that array back to function a (which called function b).
When I iterate through the returned array, the contents are all undefined. Off the cuff I figure that the JS garbage collector is probably involved here. How would I go about fixing this?
Sincerely,
mj
function a()
{
var x = b();
for( var v in x ){
//print out v.id and v.name
}
}
function b()
{
var y = new Array();
var m = new Object();
var n = new Object();
m.id = 1;
n.id = 2;
m.name = "alpha";
n.name = "bravo";
y.push( m );
y.push( n );
return y;
}

The problem is how you are "iterating" through your array. You are using the for-in statement, and this statement should be used to enumerate object properties, not to iterate over arrays or array-like objects.
From your code:
for( var v in x ){
//print out v.id and v.name
}
The for-in statement in every iteration will feed v with the name of each property, since you are using an array in your example, v will be '0', '1', etc.
You could access x[v] but I really encourage you to use a sequential for loop, for example:
for (var i = 0; i < x.length; i++) {
alert(x[i].id);
alert(x[i].name);
}
There are many reasons why to avoid for-in, when your purpose is "iterate" over numeric indexes on array like objects, see the following questions for more information:
Loop through array in JavaScript
JavaScript “For …in” with Arrays

You should not interate over an array in that way. You are looping through all of the properties/methods of the array, etc.
You can see this if you alert v http://jsfiddle.net/Xk7yB/
If you use a regular for loop, it works fine:
function a()
{
var x = b();
for(var i=0; i<x.length; i++){
alert(x[i].name);
}
}
http://jsfiddle.net/Xk7yB/1/

If you're using jQuery, you can also use:
$.each(x,function(){
alert(this.id);
alert(this.name);
});
The jQuery $.each() is most similar to the foreach mechanism you are used to.

Related

for loop or for-in loop [duplicate]

Do you think there is a big difference in for...in and for loops? What kind of "for" do you prefer to use and why?
Let's say we have an array of associative arrays:
var myArray = [{'key': 'value'}, {'key': 'value1'}];
So we can iterate:
for (var i = 0; i < myArray.length; i++)
And:
for (var i in myArray)
I don't see a big difference. Are there any performance issues?
The choice should be based on the which idiom is best understood.
An array is iterated using:
for (var i = 0; i < a.length; i++)
//do stuff with a[i]
An object being used as an associative array is iterated using:
for (var key in o)
//do stuff with o[key]
Unless you have earth shattering reasons, stick to the established pattern of usage.
Douglas Crockford recommends in JavaScript: The Good Parts (page 24) to avoid using the for in statement.
If you use for in to loop over property names in an object, the results are not ordered. Worse: You might get unexpected results; it includes members inherited from the prototype chain and the name of methods.
Everything but the properties can be filtered out with .hasOwnProperty. This code sample does what you probably wanted originally:
for (var name in obj) {
if (Object.prototype.hasOwnProperty.call(obj, name)) {
// DO STUFF
}
}
FYI - jQuery Users
jQuery's each(callback) method uses for( ; ; ) loop by default, and will use for( in ) only if the length is undefined.
Therefore, I would say it is safe to assume the correct order when using this function.
Example:
$(['a','b','c']).each(function() {
alert(this);
});
//Outputs "a" then "b" then "c"
The downside of using this is that if you're doing some non UI logic, your functions will be less portable to other frameworks. The each() function is probably best reserved for use with jQuery selectors and for( ; ; ) might be advisable otherwise.
there are performance differences depending on what kind of loop you use and on what browser.
For instance:
for (var i = myArray.length-1; i >= 0; i--)
is almost twice as fast on some browsers than:
for (var i = 0; i < myArray.length; i++)
However unless your arrays are HUGE or you loop them constantly all are fast enough. I seriously doubt that array looping is a bottleneck in your project (or for any other project for that matter)
Note that the native Array.forEach method is now widely supported.
Updated answer for 2012 current version of all major browsers - Chrome, Firefox, IE9, Safari and Opera support ES5's native array.forEach.
Unless you have some reason to support IE8 natively (keeping in mind ES5-shim or Chrome frame can be provided to these users, which will provide a proper JS environment), it's cleaner to simply use the language's proper syntax:
myArray.forEach(function(item, index) {
console.log(item, index);
});
Full documentation for array.forEach() is at MDN.
The two are not the same when the array is sparse.
var array = [0, 1, 2, , , 5];
for (var k in array) {
// Not guaranteed by the language spec to iterate in order.
alert(k); // Outputs 0, 1, 2, 5.
// Behavior when loop body adds to the array is unclear.
}
for (var i = 0; i < array.length; ++i) {
// Iterates in order.
// i is a number, not a string.
alert(i); // Outputs 0, 1, 2, 3, 4, 5
// Behavior when loop body modifies array is clearer.
}
Using forEach to skip the prototype chain
Just a quick addendum to #nailer's answer above, using forEach with Object.keys means you can avoid iterating over the prototype chain without having to use hasOwnProperty.
var Base = function () {
this.coming = "hey";
};
var Sub = function () {
this.leaving = "bye";
};
Sub.prototype = new Base();
var tst = new Sub();
for (var i in tst) {
console.log(tst.hasOwnProperty(i) + i + tst[i]);
}
Object.keys(tst).forEach(function (val) {
console.log(val + tst[val]);
});
I second opinions that you should choose the iteration method according to your need. I would suggest you actually not to ever loop through native Array with for in structure. It is way slower and, as Chase Seibert pointed at the moment ago, not compatible with Prototype framework.
There is an excellent benchmark on different looping styles that you absolutely should take a look at if you work with JavaScript. Do not do early optimizations, but you should keep that stuff somewhere in the back of your head.
I would use for in to get all properties of an object, which is especially useful when debugging your scripts. For example, I like to have this line handy when I explore unfamiliar object:
l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);
It dumps content of the whole object (together with method bodies) to my Firebug log. Very handy.
I'd use the different methods based on how I wanted to reference the items.
Use foreach if you just want the current item.
Use for if you need an indexer to do relative comparisons. (I.e. how does this compare to the previous/next item?)
I have never noticed a performance difference. I'd wait until having a performance issue before worrying about it.
here is something i did.
function foreach(o, f) {
for(var i = 0; i < o.length; i++) { // simple for loop
f(o[i], i); // execute a function and make the obj, objIndex available
}
}
this is how you would use it
this will work on arrays and objects( such as a list of HTML elements )
foreach(o, function(obj, i) { // for each obj in o
alert(obj); // obj
alert(i); // obj index
/*
say if you were dealing with an html element may be you have a collection of divs
*/
if(typeof obj == 'object') {
obj.style.marginLeft = '20px';
}
});
I just made this so I'm open to suggestions :)
With for (var i in myArray) you can loop over objects too, i will contain the key name and you can access the property via myArray[i]. Additionaly, any methods you will have added to the object will be included in the loop, too, i.e., if you use any external framework like jQuery or prototype, or if you add methods to object prototypes directly, at one point i will point to those methods.
Watch out!
If you have several script tags and your're searching an information in tag attributes for example, you have to use .length property with a for loop because it isn't a simple array but an HTMLCollection object.
https://developer.mozilla.org/en/DOM/HTMLCollection
If you use the foreach statement for(var i in yourList) it will return proterties and methods of the HTMLCollection in most browsers!
var scriptTags = document.getElementsByTagName("script");
for(var i = 0; i < scriptTags.length; i++)
alert(i); // Will print all your elements index (you can get src attribute value using scriptTags[i].attributes[0].value)
for(var i in scriptTags)
alert(i); // Will print "length", "item" and "namedItem" in addition to your elements!
Even if getElementsByTagName should return a NodeList, most browser are returning an HTMLCollection:
https://developer.mozilla.org/en/DOM/document.getElementsByTagName
For in loops on Arrays is not compatible with Prototype. If you think you might need to use that library in the future, it would make sense to stick to for loops.
http://www.prototypejs.org/api/array
I have seen problems with the "for each" using objects and prototype and arrays
my understanding is that the for each is for properties of objects and NOT arrays
If you really want to speed up your code, what about that?
for( var i=0,j=null; j=array[i++]; foo(j) );
it's kinda of having the while logic within the for statement and it's less redundant. Also firefox has Array.forEach and Array.filter
A shorter and best code according to jsperf is
keys = Object.keys(obj);
for (var i = keys.length; i--;){
value = obj[keys[i]];// or other action
}
for(;;) is for Arrays : [20,55,33]
for..in is for Objects : {x:20,y:55:z:33}
Use the Array().forEach loop to take advantage of parallelism
Be careful!!!
I am using Chrome 22.0 in Mac OS and I am having problem with the for each syntax.
I do not know if this is a browser issue, javascript issue or some error in the code, but it is VERY strange. Outside of the object it works perfectly.
var MyTest = {
a:string = "a",
b:string = "b"
};
myfunction = function(dicts) {
for (var dict in dicts) {
alert(dict);
alert(typeof dict); // print 'string' (incorrect)
}
for (var i = 0; i < dicts.length; i++) {
alert(dicts[i]);
alert(typeof dicts[i]); // print 'object' (correct, it must be {abc: "xyz"})
}
};
MyObj = function() {
this.aaa = function() {
myfunction([MyTest]);
};
};
new MyObj().aaa(); // This does not work
myfunction([MyTest]); // This works
There is an important difference between both. The for-in iterates over the properties of an object, so when the case is an array it will not only iterate over its elements but also over the "remove" function it has.
for (var i = 0; i < myArray.length; i++) {
console.log(i)
}
//Output
0
1
for (var i in myArray) {
console.log(i)
}
// Output
0
1
remove
You could use the for-in with an if(myArray.hasOwnProperty(i)). Still, when iterating over arrays I always prefer to avoid this and just use the for(;;) statement.
Although they both are very much alike there is a minor difference :
var array = ["a", "b", "c"];
array["abc"] = 123;
console.log("Standard for loop:");
for (var index = 0; index < array.length; index++)
{
console.log(" array[" + index + "] = " + array[index]); //Standard for loop
}
in this case the output is :
STANDARD FOR LOOP:
ARRAY[0] = A
ARRAY[1] = B
ARRAY[2] = C
console.log("For-in loop:");
for (var key in array)
{
console.log(" array[" + key + "] = " + array[key]); //For-in loop output
}
while in this case the output is:
FOR-IN LOOP:
ARRAY[1] = B
ARRAY[2] = C
ARRAY[10] = D
ARRAY[ABC] = 123

How to access values of array in javascript

Code:
var testarray = [];
var test1 = "ashutosh";
var test2 = "ashutosh2";
if (test1 != test2) {
testarray.push = "ashutosh3";
testarray.push = "ashutosh4";
alert(testarray.length);
}
if (testarray.length != 1) {
alert(testarray.length);
alert(testarray[testarray.length - 1]);
alert(testarray[testarray.length - 2]);
}
But when all the alerts are showing up undefined. I have no clue why is this happening.
push is a function, not a property, so instead of
testarray.push="ashutosh3";
it's
testarray.push("ashutosh3");
Here's how I'd update that code, FWIW, but I think the only substantive change is doing the push correctly and using >= 2 rather than != 1 in the length check at the end (since otherwise if the array is empty you're looking at entries -1 and -2, which will be undefined):
var testarray = [];
var test1 = "ashutosh";
var test2 = "ashutosh2";
if (test1 !== test2) {
testarray.push("ashutosh3");
testarray.push("ashutosh4");
alert(testarray.length);
}
if(testarray.length >= 2) {
alert(testarray.length);
alert(testarray[testarray.length-1]);
alert(testarray[testarray.length-2]);
}
T.J. Crowder already answer the issue with push but I'm guessing you are new to JavaScript so here are some useful tips I wished knew earlier.
For Each Loops
Instead of writing a standard for loop, you can use a forEach loop.
for( i in testArray ){
console.log( i );
}
Objects
Till hashtables and modules make their appearance to JS, we are left with using arrays. Here is the easiest method I know of to make an object.
var ArrayUtils = {
"print" : function(array) {
console.log(array);
}
}
Since ArrayUtils is an list, you can extend it using either dot or bracket notation
ArrayUtils["size"] = function(array){
return array.length;
}
ArrayUtils.indexOf = function(array, i){
return array[i];
}
Higher-Order Functions
Arrays in JavaScript come with a built-in map, reduce and filter functions. These three functions are highly useful when it comes to writing elegant code.
Map, passes each element in an sequence into a function
testArray.map( function(i){ console.log(i); } );
Reduce, well reduces the array into a single value. In this example i'm calculating the sum of the array
testArray.reduce( function(x,y) { return x+y; } );
Filter, as you could guess removes elements from an array. In JS, .filter() returns a new array
testArray = testArray.filter( function(i) { return ( i > 0 ); } );
I also read that JS has iterator and generator support. They are powerful iteration tools and worth checking out if you are going to heavily use iteration in your code base. I don't so, it's been something I put off as a todo.

sum index in JavaScript foreach

In the following code sample i get a strange behavior
var data = ['xxx', 'yyy'];
for (var i in data)
{
var a = i;
var b = data[i];
}
The two first iterations works just fine. I get index "0" and "1" in i, but then it loops one extra time and now the i is "sum". Is this by design or what is this extra iteration used for? The result in my case is always empty and it messes up my code. Is there a way to not do his extra loop?
BR
Andreas
It looks like you (or some other code you've included) have added extra properties onto the Array prototype. What you should be doing is checking to see whether the object you're iterating over actually has that property on itself, not on its prototype:
for (i in data) {
if (data.hasOwnProperty(i)) {
a = i;
b = data[i];
}
}
That said, you should never use for .. in on arrays. Use a regular for loop.
See here for more information: http://yuiblog.com/blog/2006/09/26/for-in-intrigue/
You are looping through an Array, not through an Object. For arrays it's better to use:
for (var i=0; i<data.length; i=i+1){
/* ... */
}
In your loop every property of the Array object is taken into account. That makes the for ... in loop for array less predictable. In your case it looks like sum is a property (method) that's added to Array.prototype elsewhere in your code.
There are more ways to loop through arrays. See for example this SO-question, or this one
Just for fun, a more esoteric way to loop an array:
Array.prototype.loop = function(fn){
var t = this;
return (function loop(fn,i){
return i ? loop(fn,i-1).concat(fn(t[i-1])) : [];
}(fn,t.length));
}
//e.g.
//add 1 to every value
var a = [1,2,3,4,5].loop(function(val){return val+1;});
alert(a); //=> [2,3,4,5,6]
//show every value in console
var b = [1,2,3,4,5].loop(function(val){return console.log(val), val;});
Here's a way to safely iterate.
var data = ['xxx', 'yyy'];
for (var i = 0; i < data.length; i++)
{
var a = i;
var b = data[i];
}
What you are getting is an method coming from extending the Array object, I guess you are using some library where is something like
Array.prototype.sum = function () {...};
Perhaps setting data like this would work better: var data = {0:'xxx', 1:'yyy'};
First of all data is an object. Try to add console.log(a); and console.log(b); inside your loop and you'll see.

JavaScript Array

I usually script/program using python but have recently begun programming with JavaScript and have run into some problems while working with arrays.
In python, when I create an array and use for x in y I get this:
myarray = [5,4,3,2,1]
for x in myarray:
print x
and I get the expected output of:
5
4
3
..n
But my problem is that when using Javascript I get a different and completely unexpected (to me) result:
var world = [5,4,3,2,1]
for (var num in world) {
alert(num);
}
and I get the result:
0
1
2
..n
How can I get JavaScript to output num as the value in the array like python and why is this happening?
JavaScript and Python are different, and you do things in different ways between them.
In JavaScript, you really should (almost) always iterate over an array with a numeric index:
for (var i = 0; i < array.length; ++i)
alert(array[i]);
The "for ... in" construct in JavaScript gives you the keys of the object, not the values. It's tricky to use on an array because it operates on the array as an object, treating it no differently than any other sort of object. Thus, if the array object has additional properties — which is completely "legal" and not uncommon — your loop will pick those up in addition to the indexes of the "normal" array contents.
The variable num contains the array item's index, not the value. So you'd want:
alert(world[num])
to retrieve the value
The for var in... loop in JavaScript puts the keys in the variable instead of the actual value. So when using for var ... you should do something like this:
var world = [5, 4, 3, 2, 1];
for ( var key in world ) {
var value = world[key];
alert(key + " = " + value);
}
And note that this way of looping is best used when you're using objects instead of arrays. For arrays use the common:
for ( var i = 0, j = arr.length; i < j; i++ ) { ... }
Or if you're targeting modern browser you can use the forEach-method of arrays:
var arr = [1, 2, 3];
arr.forEach(function(num) {
alert(num);
});
The for...in loop loops over all key elements; not the values.
I would recommend you to use
for(var i=0; i<arr.length; i++){
alert(arr[i]);
}
When you use the in operator num becomes a key. So simply use this key to get a value out of the array.
var world = [5,4,3,2,1]
for (var num in world) {
alert(world[num]);
}
try this.
var world = [5,4,3,2,1]
for(var i=0;i<world.length;i++){
alert(world[i])
}
Because javascript in your case is printing the index of the element, not the value.
the result you got is just element index,if you want to get element value
your code should like this
var world = [5,4,3,2,1]
for (var num in world) {
alert(world[num]);
}
The for in iteration in JavaScript works only for the object data type. The way it works is that it lets you iterate over the attributes of an object. arrays are objects in JavaScript, but the for in only works on its attributes, not the array values.
For example you might define an array as such:
var arr = [1,2,3];
And you can assign attributes to this array, because it's actually an object:
arr.foo = "bar";
arr["1"] = 2;
Now when you use the for in iteration method you will be able to iterate over the attributes we just assigned above;
for(var i in arr) console.log(i);
To iterate over the actual array values you need to use the for(var i=0; i<arr.length; i++) construct.
Hope this helps.
In javascript it's advised to loop Arrays different from looping Objects. You are using an object loop, which may return unexpected result (for instance if the Array.prototype was extended with custom methods you would iterate those too, and it does't guarantee the order of the array is preserved). There are many ways to loop through an array, using it's index:
// regular
var arr = [1,2,3,4,5]
,i
;
for (i=0;i<arr.length;i++) {
console.log(arr[i]);
}
// using while
var arr = [1,2,3,4,5]
,i = 0
;
while ((i = i + 1)<arr.length) {
console.log(arr[i]);
}
// using while reversed
var arr = [1,2,3,4,5]
,i = arr.length
;
while ((i = i - 1) > -1) {
console.log(arr[i]);
}
Note: Why not use i++ or i--? To avoid confusion, index out of range-errors and to satisfy JSLint

JavaScript: Split array into individual variables

Considering this data structure:
var vehicles = [
[ "2011","Honda","Accord" ],
[ "2010","Honda","Accord" ],
.....
];
Looping through each vehicles item, is there a way to reassign the array elements to individual variables all in one shot, something like:
for (i = 0; i < vehicles.length; i++) {
var(year,make,model) = vehicles[i]; // doesn't work
.....
}
... I'm trying to get away from doing:
for (i = 0; i < vehicles.length; i++) {
var year = vehicles[i][0];
var make = vehicles[i][1];
var model = vehicles[i][2];
.....
}
Just curious since this type of thing is available in other programming languages. Thanks!
Now it is possible using ES6's Array Destructuring.
As from Docs:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Consider the following example:
let [a, b, c] = [10, 20, 30];
console.log(a); // output => 10
console.log(b); // output => 20
console.log(c); // output => 30
As with your data, .forEach() method can also be used for iterating over array elements along with Array Destructuring:
let vehicles = [
[ "2011","Honda","Accord" ],
[ "2010","Honda","Accord" ]
];
vehicles.forEach(([year, make, model], index) => {
// ... your code here ...
console.log(`${year}, ${make}, ${model}, ${index}`);
});
References:
Array Destructuring
Array.prototype.forEach()
Arrow Functions
Template Literals
No unfortunately there is not a method to do this currently XBrowser. (that I'm aware of).
Relatively soon it's possible cross browser, see link:
https://developer.mozilla.org/en/New_in_JavaScript_1.7
(In PHP there is "list" which will do exactly what you wish, nothing similar XBrowser for javascript yet)
Of course relatively soon could mean anything etc. (Thanks Felix for pointing out my errors in this)
edit: This is now available see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Array_destructuring
Probably the closest you'll currently get in javascript is to eliminate the redundant var and separate the statements with a comma separator.
for (i = 0; i < vehicles.length; i++) {
var year = vehicles[i][0], make = vehicles[i][1], model = vehicles[i][2];
.....
}
or you could shorten it a bit more like this:
for (i = 0; i < vehicles.length; i++) {
var v = vehicles[i], year = v[0], make = v[1], model = v[2];
.....
}
The closest alternative that I could think of is using a function and using apply() to call it. Passing an array, it would get passed as each argument.
function vehicle(year, make, model) {
// do stuff
}
for (i = 0; i < vehicles.length; i++) {
vehicle.apply (this, vehicles[i]);
}
Or an anonymous function:
for (i = 0; i < vehicles.length; i++) {
(function(year, make, model) {
// do stuff
}).apply(this, vehicles[i]);
}
Unpacking array into separate variables in JavaScript
The destructuring assignment syntax is a JavaScript expression that
makes it possible to unpack values from arrays, or properties from objects,into distinct variables.
let array = [2,3];
[a,b] = array;// unpacking array into var a and b
console.log(a); //output 2
console.log(b); //output 3
let obj = {name:"someone",weight:"500pounds"};
let {name,weight} = obj; // unpacking obj into var name and weight
console.log(name);// output someone
console.log(weight);//output 500pounds
Source

Categories