loop variable declaration style in for loop - javascript

var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return obj;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
return obj;
};
In the implementation of _.each method in underscore.js, the loop variables are set as follows.
for (var i = 0, length = obj.length; i < length; i++)
why is the length variable explicitly declared?, isn't the following code more succinct?
for (var i = 0; i < obj.length; i++)

There are a couple possible reasons to declare the separate length variable:
Caching it locally in its own variable can be faster than referencing it as a property every time through the loop.
In some cases, the array length may grow during the iteration and you may not want to iterate newly added elements.

Related

Using pure function with Javascript object

Suppose I have a code like this:
function example() {
const obj = {};
for (let i = 0; i < 10; i++) {
for (let j = 0; j< 10; j++) {
if (obj[i] == undefined) {
obj[i] = 0;
}
if (obj[j] == undefined) {
obj[j] = 0;
} else {
obj[i] += i;
obj[j] += j;
}
}
}
}
Here you can see:
if (obj[i] == undefined) {
obj[i] = 0;
}
I check if i not in obj I assign the key i inside obj with 0 else I do nothing, I do sample with j.
The code is duplicated and I do not want to repeat my self, it is bad practice so I make another function to apply for i and j like this:
function initObjWithValue(obj, keys) {
for (const key of keys) {
if (obj[key] === undefined) {
obj[key] = 0;
}
}
}
The function is very easy to understand right? It has first parameter as an object and the second parameter is an array of keys to check. Now I can refactor my code like this:
function example() {
const obj = {};
for (let i = 0; i < 10; i++) {
for (let j = 0; j< 10; j++) {
initObjWithValue(obj, [i, j]);
obj[i] += i;
obj[j] += j;
}
}
}
The code is clearer but as you can see in my function initObjWithValue, it mutates obj and I think it is not good. Here is the quote from Wiki page:
In computer programming, a pure function is a function that has the following properties:
Its return value is the same for the same arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams from I/O devices).
And I got stuck at this point, how can I do not repeat my self and I can achieve pure function in this case?
You could instead make initObjectWithValue return a new object, which you can then merge with your current obj. This way, all you're doing is reading from obj, and not mutating it within initObjectWithValue:
function initObjWithValue(obj, keys) {
const tmp = {};
for (const key of keys) {
if (!(key in obj)) {
tmp[key] = 0;
}
}
return tmp;
}
function example() {
const obj = {};
for (let i = 0; i < 10; i++) {
for (let j = 0; j< 10; j++) {
Object.assign(obj, initObjWithValue(obj, [i, j])); // merge the return with current object
obj[i] += i;
obj[j] += j;
}
}
return obj;
}
console.log(example());
Instead of checking
(obj[i] == undefined)
write
(typeof obj[i] == undefined)

Why the null checking of path.length in deepGet function is placed in end of it?

deepGet function in underscore.js implements like this:
var deepGet = function(obj, path) {
var length = path.length;
for (var i = 0; i < length; i++) {
if (obj == null) return void 0;
obj = obj[path[i]];
}
return length ? obj : void 0;
};
Why it's not implement like this:
var deepGet = function(obj, path) {
var length = path.length;
if (!length)
return void 0;
for (var i = 0; i < length; i++) {
if (obj == null) return void 0;
obj = obj[path[i]];
}
return obj;
};
If 'length' is null or zero, in first one run 2 checking(for,?:) but in second one only 1 checking(if(!length))
I'm learning javascript and I want to know why?

Find the length of an specific object within an array

In the following code there is a console log of obj['mn'] which returns the length of that specific object which is 2. The problem with the code is that it doesn't count the multidimentional array, and only it counts the first array. The result should be 4 because there are 4 'mn' in total. What am I doing wrong?
var arr = [['ab','pq','mn','ab','mn','ab'],'mn','mn'];
var obj = { };
for (var i = 0, j = arr.length; i < j; i++) {
if (obj[arr[i]]) {
obj[arr[i]]++;
}
}
console.log(obj['mn']);
This is what you're looking for:
var arr = [['ab','pq','mn','ab','mn','ab'],'mn','mn'];
var obj = { };
function count(arr, obj) {
for (var i = 0, j = arr.length; i < j; i++) {
if (Array.isArray(arr[i])) {
count(arr[i], obj);
}
else if (typeof obj[arr[i]] !== 'undefined') {
obj[arr[i]]++;
}
else {
obj[arr[i]] = 1;
}
}
return obj;
}
console.log(count(arr, obj));
This is a recursive implementation. When it gets to an array, the recursion get one level deeper.
You are calling obj[['ab','pq','mn','ab','mn','ab']], which is obviously not what you wanted.
You need a depth first search.
If arr[i] is an array, then you need to loop through that array.

Search of object indexes

I trying to get indexes of all the
<div>
tags. This is how I am trying to do it. How can I correct this to show me all the matching indexes?
allNodes = [];
nodeList=document.querySelectorAll("*");
for(var i = 0, n; n = nodeList[i]; ++i) allNodes.push(n);
function getAllIndexes(arr, val) {
var indexes = [], i;
for(i = 0; i < arr.length; i++)
if (arr[i] === val)
indexes.push(i);
return indexes;
}
testing = getAllIndexes(allNodes,"HTMLDivElement");
alert(testing);

How could I delete an item from an array by the item's name?

Like I have an array Array('one', 'three', 'two');, and, say, I want to delete the item three, how would I do it?
var a = ['one', 'three', 'two'];
a.splice(a.indexOf('three'), 1);
alert(a);
for browsers that don't support indexOf there's a workaround
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/IndexOf#Compatibility
function RemoveArrayValue(arr, val)
{
var result = [], //empty array
j = 0, i, len = arr.length;
for(i = 0; i < len; ++i)
if(arr[i] != val)
result[j++] = val;
return result;
}
BTW:
the indexOf method is not part of the Javascript Array object under IE (also not part of IE8), but of the String object. If you want the indexOf method to be part of the JS Array object you must declare this in your code:
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(val)
{
for(var i = 0, len = this.length; i < len; ++i)
if(this[i] === val)
return i;
return -1;
}
}

Categories