This is the code :
i'm storing the function body inside each element of "resultArr"
, the problem is when i call the stored function _class[0]()i can't reach the exact i it's always 4 !
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push(function(){console.log('Is', nameArr[i], 'present?', i);});
}
return resultArrultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
i think it's obvious if i call any item of _class i.e _class[0]() the index will be 4 and the name will be "undefined"
So how wan i solve this problem, i saw some ppl use the apply native function, but i think it works only if we store the function name not the body of a given function
In this case, all the closures inside checkAttendanceFunc point to a reference of the i and nameArr variable.
When the loop is done, i's value is 4 for all the functions you generated, what you need is copying i each time you pass it to a closure.
There are several ways for you to achieve this:
Immediately call the function
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push(function(index){
return function(){
console.log('Is', nameArr[index], 'present?', index);
}
}(i));
}
return resultArr;
};
Here you're passing an argument fo the closure and you call it immediately. In this case, i is getting copied and the function has its own value named index.
Use another function that iterates on the array
In this case I'm using Array.forEach
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
nameArr.forEach(function (value, index){
resultArr.push(function() {
console.log('Is', value, 'present?', index);
});
});
return resultArr;
};
In this case the functions created recieve a copy of value and index, which means they will always point to the same values.
Still not sure I understand the intent of this code, but here's a working version that does what I think you're trying to do:
var students = ["alex", "brownex", "chris", "mack"];
var _class = students.map(function(name, i) {
return function() {
console.log('Is', name, 'present?', i);
};
});
See it in action here.
If you're really just looking for how to make it work with a for-loop, you could always capture it like this:
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push((function(idx) {
return function() {
console.log('Is', nameArr[idx], 'present?', idx);
};
})(i));
}
return resultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
Similarly, you can also use .bind():
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push((function(idx) {
console.log('Is', nameArr[idx], 'present?', idx);
}).bind(null, i));
}
return resultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
Either way, I personally find the .map() solution much more elegant and readable.
Related
var filterKeys = ["hello this is javascript", "Movies"];
var title= "Hello"
searchKeyInNo = keySearch(filterKeys, title)
function KeySearch(filteredArray, searchKey) {
var flag=0
for (var i = 0; i<filteredArray.count; i++) {
//array operations
flag=1
}
return flag
}
var filterKeys = ["hello this is javascript", "Movies"];
var title= "Hello"
searchKeyInNo = keySearch(filterKeys, title)
function KeySearch(filteredArray, searchKey) {
var tempArray = filteredArray
var flag=0
for (var i = 0; i<tempArray.count; i++) {
//array operations
flag=1
}
return flag
}
Can we use passed array as paramneter as a function array?
Can we pass and use the entire array as argument?
I even tried the second piece of code that I added a new array to copy the argument array to process the function scoped array.
UPDATE: VS Code never showed up suggestion for argumentarray.length. Thanks. WORKS NOW!
Try this. You were using .count instead of .length on the filtered array to get the count of elements.
function KeySearch(filteredArray, searchKey)
{
var flag=0
for (var i = 0; i<filteredArray.length; i++)
{
if(filteredArray[i].toLowerCase()
.includes(searchKey.toLowerCase()))
{
flag++
}
}
return flag
};
console.log(KeySearch(["hello this is javascript", "Movies"], "Hello"))
I currently have an object that adds itself to an array whenever a new one is created. Eventually, I want to remove all of the references in the array so I can add new ones.
I've created an object method (this.removeFromArray()) that looks for itself in the array and splices itself out. removeAll() runs a for loop that makes each object in the array run removeFromArray(), so I expect that when I try to read out the items in the array, I should get nothing.
Instead, depending on the amount of objects created, I get one or two left behind. How can I fix this and have all objects in the array cleared out?
var objArray = [];
function obj(name) {
objArray.push(this);
console.log("Created "+name);
this.name = name;
this.removeFromArray = function() {
objArray.splice(
objArray.findIndex(function(e) {
return e == this;
}),
1
);
}
}
function removeAll() {
for (var i = 0; i <= objArray.length - 1; i++) {
objArray[i].removeFromArray();
}
}
var foo = new obj("foo");
var bar = new obj("bar");
var cat = new obj("cat");
var dog = new obj("dog");
var bird = new obj("bird");
removeAll();
for (var i = 0; i <= objArray.length-1; i++) { //Check the values in the array for leftovers
console.log(objArray[i].name);
}
//Expected nothing in the console but the creation messages, got foo and bar instead
If you want to simply delete all the created object, edit removeAll() function like below:
Note that you have to create a variable for objArray.length, not directly put the objArray.length to for() loop.
function removeAll() {
var len = objArray.length;
for (var i = 0; i <= len - 1; i++) {
objArray.splice(0,1);
}
}
better way to achieve this would be to utilize inheritance through prototype. it is better than creating a function inside the constructor object.
var objArray = [];
function Obj(name) {
this.name = name;
objArray.push(this);
}
Obj.prototype.removeFromArray = function() {
var i = -1,
len = objArray.length,
removed = null;
while (++i < len) {
if (objArray[i] === this) {
removed = objArray.splice(i, 1);
removed = null; //nullify to free memory, though not that necessary
break;
}
}
};
Obj.prototype.removeAll = function() {
var len = objArray.length,
removed = null;
//note that i started from the last item to remove to avoid index out of range error
while (--len >= 0) {
removed = objArray.splice(len, 1);
removed = null; //nullify to free memory, though not that necessary
}
};
I'm working on a tutorial that explains functional programming. He asked me to come with a solution and it worked, but his solution uses the .bind method of the function.
Is there a difference between our solutions other than the syntax?
function mapForEach(arr, fn) {
var newArr = [];
for(var i = 0; i < arr.length; i++){
newArr.push(fn(arr[i]));
}
return newArr;
}
var arr1 = [1,2,3,4,5];
var checkPassedLimitWithBind = function(limiter){
return function (limiter, item) {
return item >= limiter;
}.bind(this, limiter);
};
var checkPassedLimitWithClosure = function(limiter){
return function (item) {
return item >= limiter;
};
};
var notPassed3 = mapForEach(arr1, checkPassedLimitWithBind(3));
var doesNotPass3 = mapForEach(arr1, checkPassedLimitWithClosure(3));
alert(notPassed3);
alert(doesNotPass3);
The examples can be found here as well:
https://jsfiddle.net/podbarron/73m86cj3/
There is absolutely no behavior difference because that function does not use this.
Otherwise it would be different, yes:
var checkPassedLimitWithBind = function(limiter) {
return function (limiter, item) {
return this == item;
}.bind(this, limiter);
};
var checkPassedLimitWithClosure = function(limiter) {
return function (item) {
return this == item;
};
};
console.log( checkPassedLimitWithBind.call(123)(123) ); // true
console.log( checkPassedLimitWithClosure.call(123)(123) ); // false
The bind solution is unnecessarily complicated. There's no need to partially apply the limiter value there since the function can pretty much access it directly.
Both will end up working the same way. However, it can be different if the variable ever gets reassigned (you'd never want to do it with function arguments).
var checkPassedLimitWithBind = function(limiter){
var fn = function (limiter, item) {
return item >= limiter;
//limiter === argument value for limiter parameter
}.bind(this, limiter);
limiter = 5;
return fn;
};
var checkPassedLimitWithClosure = function(limiter){
var fn = function (item) {
return item >= limiter;
//limiter === 5 all the time
};
limiter = 5;
return fn;
};
Answering the post title: Basically, the closure will have access to whatever value that reference is holding. When you bind the function you'll get that specific value passed down.
I created an object called "Jarz". Then added an object within it called 'cat'. Then I made a function to search within the Jarz object for an object called 'cat', which works. However for every object after 'cat' that I add to 'Jarz' the function will not find it in the search. Only the first run ever works. Here is the code:
var Jarz = {};
Jarz['cat'] = {};
Here is the function:
function doesObjExist(ObjName){
var tmpArr = Object.keys(Jarz);
for(var i = 0; i < tmpArr.length; i++){
if(tmpArr[i] === ObjName){
return true;
}
else {
return false;
}
}
}
When I run it on the first object 'cat' it returns true. But any obj I make after that returns false. ie:
Jarz['hat'] = {};
doesObjExist('hat') // returns false
I cant seem to find what is missing here. Any help is appreciated, thanks.
Its because when you call it with hat,it is checking first for cat as it is false your returning from the loop so it wont execute further to check for hat
change this to
var Jarz = {};
Jarz['cat'] = {};
console.log(doesObjExist('cat'));
Jarz['hat'] = {};
console.log(doesObjExist('hat'));
function doesObjExist(ObjName) {
var tmpArr = Object.keys(Jarz);
var count = 0;
for (var i = 0; i < tmpArr.length; i++) {
if (tmpArr[i] === ObjName) {
return true;
} else {
count++;
}
}
if (count >= tmpArr.length)
return false;
}
Hope this helps
I have a complex array of objects with nested arrays. The following works to extract certain objects, but it's one of the ugliest things I've written.
Is there some javascript dark magic to do this elegantly?
function getEighthInsertionBlocks() {
var struct = Lifestyle.Pagination.structure;
var blocks = [];
for (var i = 0; i<struct.length; i++) {
var page = struct[i];
var layers = page.children;
for (var j=0; j<layers.length; j++) {
var layer = layers[j];
if (layer.className === 'EighthPageLayer' ) {
var rows = layer.children;
for (var k=0; k<rows.length; k++) {
var row = rows[k];
eBlocks = row.children;
for (var l=0; l<eBlocks.length; l++) {
blocks.push(eBlocks[l]);
}
}
}
}
}
return blocks;
}
Not that I'm a big fan of code golf, but ... this is horrible.
You could write a generic iterator, which would reduce the code into sequential blocks:
var iterator = function(collection, callback){
var length = collection.length;
var results = [];
var result;
for (var i = 0; i < collection.length; i++){
result = callback(colleciton[i], i);
if (result){
results = results.concat(result);
}
}
return results;
};
function getEighthInsertionBlocks() {
var struct = Lifestyle.Pagination.structure;
var layers = iterator(struct, function(page){ return page.children; });
var rows = iterator(layers, function(layer){
return layer.className === 'EighthPageLayer' ? layer.children : null;
});
return iterator(rows, function(eBlocks, index){ return eblocks[index]; });
}
I usually tend to like using forEach for the readability but this is subjective.
function isEighthPageLayer(layer){
return layer.className === "EighthPageLayer"
}
function getEighthInsertionBlocks(struct) {
var blocks = [];
struct.forEach(function(page){
page.layers
.filter(isEighthPageLayer)
.forEach( function(layer) {
layer.children.forEach(function(row){
row.children.forEach(function(eBlocks){
blocks.push(eBlocks);
});
});
});
});
});
return blocks;
}
This is an interesting challenge. To avoid deep nesting, you need a generic iterator that you can use recursively, yet there are a few special cases in your iteration. So, I tried to create a generic iterator that you can pass an options object to in order to specify the special conditions. Here's what I came up with. Since I don't have a sample data set, this is untested, but hopefully you see the idea:
function iterateLevel(data, options, level, output) {
console.log("level:" + level);
console.log(data);
var fn = options[level] && options[level].fn;
for (var i = 0; i < data.length; i++) {
if (!fn || (fn(data[i]) === true)) {
if (level === options.endLevel) {
output.push(data[i]);
} else {
iterateLevel(data[i].children, options, level + 1, output);
}
}
}
}
var iterateOptions = {
"1": {
fn: function(arg) {return arg.className === 'EighthPageLayer'}
},
"endLevel": 3
}
var blocks = [];
iterateLevel(Lifestyle.Pagination.structure, iterateOptions, 0, blocks);
The idea is that the options object can have an optional filter function for each level and it tells you how many levels to go down.
Working demo: http://jsfiddle.net/jfriend00/aQs6h/