Array element are undefined Javascript - javascript

The array elements in Bind are undefined even though there is data in bindInfo.
Any suggestions.
let bindinfo =
{
clientid: 1,
clientname: 'Web Client',
nowutc: now_utc,
bindlist: Bindings(this.props.bindDetails)
}
Bindings(bin)
{
var Bind = [];
Bind = bin.map(bindItem => {
var bindInfo;
bindInfo = {
bindingid: bindItem.bindId,
function: bindItem.functionName,
aggregation: bindItem.aggregation,
datalimit: bindItem.datalimit
}
Bind.push(bindInfo);
});
return Bind;
}

After the .map operation completes, bind is assigned to the result of the .map - that is, the element returned on each iteration of .map is the new array elemenet. But you never return anything from the mapper function, so even if you initially push to Bind, your later reassignment of Bind resets it.
Either use .map properly and return the item on each iteration:
const Bind = bin.map(bindItem => {
return {
bindingid: bindItem.bindId,
function: bindItem.functionName,
aggregation: bindItem.aggregation,
datalimit: bindItem.datalimit
};
});
Or (not recommended) use forEach rather than .map, and don't reassign Bind:
const Bind = [];
bin.forEach(bindItem => {
var bindInfo = {
bindingid: bindItem.bindId,
function: bindItem.functionName,
aggregation: bindItem.aggregation,
datalimit: bindItem.datalimit
}
Bind.push(bindInfo);
});
Use .map when you want to transform one array into another through the result of the call of .map. Otherwise, for generic looping, use forEach.

Related

JavaScript: Write Function that take an object and an array of functions as input args and return an array

I want to take an object and an array of functions and return an array. I am trying to use the for loop here.
I have the following code below:
const fnArr = [
function firstName() {
return this.first;
},
function lastName() {
return this.last;
},
];
const obj = { first: 'Nimit', last: 'Maru' };
function callAll(obj, fnArr){
let newArray = [];
for (let i=0; i<fnArr.length; i++){
let eachFunc = fnArr[i];
return newArray.push(eachFunc.call(obj))
}
}
callAll(obj, fnArr)
My expected output is:
['Nimit', 'Maru']
But the output from my personal code is returning: 1
Question 1: What am I doing wrong here?
////////////////////////////////////////////////////////////////////////////////////////////////////////////
Additionally, the solution I was given is below:
const fnArr = [
function firstName() {
return this.first;
},
function lastName() {
return this.last;
},
];
const obj = { first: 'Nimit', last: 'Maru' };
const callAll = (obj, fnArr) => {
return fnArr.map(fn => {
return fn.call(obj);
});
};
It produces the right answer.
Question 2: In the solution code above, why do I need the call method in "return fn.call(obj)"?
A conceptual explanation of when you need or don't need call in these types of situations would be greatly appreciated.
You are returning in each loop. So after the first loop the the function ends and code doesn't execute further.
It returns 1 because push() method returns the length of the array after adding elements to it. Initally array was empty when 1 element is added it returns 1.
You don't need to necessarily use map() just push() the element(don't return). And return the newArray after loop.
const fnArr = [
function firstName() {
return this.first;
},
function lastName() {
return this.last;
},
];
const obj = { first: 'Nimit', last: 'Maru' };
function callAll(obj, fnArr){
let newArray = [];
for (let i=0; i<fnArr.length; i++){
let eachFunc = fnArr[i];
newArray.push(eachFunc.call(obj))
}
return newArray
}
console.log(callAll(obj, fnArr))
In the solution code above, why do I need the call method in "return fn.call(obj)"?
The this binding to the function depends upon how the function is called. If the function is called as the method of the object then the object will be binded to that method.
In the above code this inside your both functions will refer to window object if they are called normally. So we want this to refer the object so we use call
Why eachFunc(obj) returns [undefined, undefined]?
When you don't use call this will refer to window object. So there is not property named first and last on window object so it returns undefined

The callback in my code seems not working and returns result without the callback function is being applied

I have written a javascript object 'myMath' as follows:
But in the 'mean' function, callback is not being called.
const myMath = {
square(x){
return x**2;
},
mean(array, callback){
if(callback){
array.map(callback);
}
const total = array.reduce((acc,x)=>acc+x);
return total/array.length;
}
};
When tried to invoke the function as follows output obtained is 2, and not 4.6666..., which is expected.
myMath.mean([1,2,3],x=>x**2);
<< 2
Why is it so ? And How can I resolve that ?
.map returns a new array. It's that one you need to work with after the map operation.
const myMath = {
square(x){
return x**2;
},
mean(array, callback){
let mapped = callback ? array.map(callback) : array;
const total = mapped.reduce((acc,x)=>acc+x);
return total/mapped.length;
}
};
console.log(myMath.mean([1,2,3],x=>x**2));
console.log(myMath.mean([1,2,3]));
Array.map is not "mutating" method, so you should save mapped value:
array = array.map(callback);

Passing arguments into map()

I am trying to use the built in map() function on an Array.from () that returns some elements using Puppeteer.
The below is the code:
let res = await page.evaluate(elementPath => {
return Array.from(document.querySelectorAll(elementPath), (cin, index) => {
return {
cs: `state is ${this.s}`, // returns state is undefined
cinemaIndex: index,
cinemaId: cin.getAttribute('data-id'),
cinemaName: cin.getAttribute('data-name'),
cinemaURL: cin.getAttribute('data-url'),
};
}, {
s: 'NSW'
});
}, `div[data-state=${cinemaState}] div.top-select-option a.eccheckbox`, cinemaState);
I am not able to assign cs with variable s or cinemaState.
Wondering if you have solution
[1,2,3,4].map(function(num, index,wholeArray){
console.log(num,index,wholeArray,this.s);
},{s:"nsw"})
maps takes two argument callback and thisArg whatever u will pass at the second arg will be accessible bi this
You can assign s to the cinemaState property in your return statement using the following method:
cinemaState: this.s,
Additionally, Array.from() has a built-in map function, so you should call the map function from within Array.from() to avoid an intermediate array:
Array.from(arrayLike, mapFn); // good
Array.from(arrayLike).map(mapFn); // bad
Lastly, you may want to use quotes around cinemaState in your attribute selector within your template literal selector string:
[data-state="${cinemaState}"] // good
[data-state=${cinemaState}] // bad
Your final code should look something like this:
let res = await page.evaluate(elementPath => {
return Array.from(document.querySelectorAll(elementPath), (cin, index) => {
return {
cinemaState: this.s,
cinemaIndex: index,
cinemaId: cin.getAttribute('data-id'),
cinemaName: cin.getAttribute('data-name'),
cinemaURL: cin.getAttribute('data-url'),
};
}, {
s: 'NSW'
});
}, `div[data-state=${cinemaState}] div.top-select-option a.eccheckbox`, cinemaState);
I am able to explain this. this is what has worked for me. I had to replace the arrow function to a traditional function
let res = await page.evaluate(elementPath => {
return Array.from(document.querySelectorAll(elementPath), function (cin, index) // changed from (cin, index) =>
{
return {
cs: `state is ${this.s}`, // returns state is undefined
cinemaIndex: index,
cinemaId: cin.getAttribute('data-id'),
cinemaName: cin.getAttribute('data-name'),
cinemaURL: cin.getAttribute('data-url'),
};
}, {
s: 'NSW'
});
}, `div[data-state=${cinemaState}] div.top-select-option a.eccheckbox`, cinemaState);

How to pass arguement to named callback in higher order functions

I'm trying to figure out how do I pass in an argument to a named callback function?
For example I have
var result = this.data;
var groupFilter = $("#groupSelect");
var functionFilter = $("#functionSelect");
var skillFilter = $("#skillSelect");
var uniqSkils = _(result).map('skill').uniq().map(populateDropdown(skillFilter));
var uniqFunctions = _(result).map('function').uniq().map(populateDropdown(functionFilter));
var uniqgroups = _(result).map('group').uniq().map(populateDropdown(groupFilter));
function populateDropdown(element) {
element.append($('<option>', {
value: item,
text: item
}))
}
Essentially the result contains dropdown values for three elements. I've created 3 arrays, I've then called uniq for obvious reasons, then I want to go through each array, each item and add it to the correct elements.
But I can't figure out how to pass in the element when using a named callback
You could have your populateDropdown return a closure that is bound to a particular element:
function populateDropdown(element) {
return function(item) {
element.append($('<option>', {
value: item,
text: item
}));
}
}

Why can I not access an array in factory while I am in a forEach loop with Angular?

I have the following question: Why is it impossible for me to access my array in a forEach loop with Angular. I have made this factory with an array and a function, within the function I have this forEach loop. Outside of the forEach loop I can acces my array with the this keyword. In the forEach loop it gives me a undefined value.
.factory("sendOrder", function () {
return {
paired: [],
send: function () {
var names = document.getElementsByTagName('input');
var ordered = document.getElementsByClassName('ordered');
var i = 0;
console.log(this.paired);//I can access it from here
angular.forEach(names, function (amount, key) {
console.log(this.paired);//Unable to access
i++;
return;
})
}
}
})
Maybe this will help. Angular lets you set the context (this) in forEach. It's one of the arguments. You don't have to set any other variables:
angular.forEach(obj, iterator, [context]);
You've passed in obj and iterator. Just pass in something for context and that will be this in the function.
Because the context of the function changes - this is not what it originally was. The usual fix is to set the original context to a variably (usually called self):
.factory("sendOrder", function () {
return {
paired: [],
send: function () {
var self = this;
var names = document.getElementsByTagName('input');
var ordered = document.getElementsByClassName('ordered');
var i = 0;
console.log(this.paired);//I can access it from here
angular.forEach(names, function (amount, key) {
console.log(self.paired);//should be fine now
i++;
return;
})
}
}
})

Categories