function makeArmy() {
let shooters = [];
for (let i = 0; i < 10; i++) {
let shooter = function() {
alert(i);
};
shooters.push(shooter);
}
return shooters;
}
let army = makeArmy();
army[0](); < -- - what is this ?
army[5](); < -- - what is this ?
Let's do this back-to-front:
let army = makeArmy();
That calls a function...
// ...and the function
function makeArmy() {
// Creates an array
let shooters = [];
// It loops from 0 to 9 pushing a new function
// into the array on each iteration
for (let i = 0; i < 10; i++) {
// Create the new function
let shooter = function() {
// I used console.log because it's much less hassle :)
console.log(i);
};
// Add the function to the array
shooters.push(shooter);
}
// And then you return the array of functions
return shooters;
}
// An array of functions!
let army = makeArmy();
// Call the first function in the array
army[0]();
// Call the fourth function in the array
army[3]();
Related
I am trying to update a specific array index with a new carrier_id and name.
However, I'm getting a puzzling assignment problem.
Comment line with Note #1 out and nData will look fine, otherwise its order property appears to get set before updateNormalizedData is called.
let data = JSON.parse('[{"order":{"po_no":"po_2019","ship_details":{"carrier_id":1044777,"method":"FREE Shipping"},"sub_total":0},"items":[{"header":{"set_no":0,"carrier_id":104777,"po_no":"po_2019"},"line":{"item_id":"ABC RE1000","line_no":0}},{"header":{"set_no":0,"carrier_id":104777,"po_no":"po_2019"},"line":{"item_id":"ABC DA1111","line_no":1}}]}]');
let numSet = 0;
let numLine = 1;
let args = {"carrier_id": 555111};
function normalizeData(data, numSet, numLine, args) {
let i = 0, j = 0, l = data.length;
let normalizedDataSet = [];
// console.log(data[i])
for (i = 0; i < l; i++) {
let m = data[i]['items'].length;
for (j = 0; j < m; j++) {
data[i]['items'][j]['order'] = { ...data[i]['order'] }; // Destructure data to assign value, not object reference
normalizedDataSet.push(data[i]['items'][j]);
}
}
// console.log('nData', normalizedDataSet);
updateNormalizedData(normalizedDataSet, numSet, numLine, args); // Note #1
}
function updateNormalizedData(normalizedDataSet, numSet, numLine, args) {
let i;
let n = normalizedDataSet.length;
let newNormal = [];
for (i = 0; i < n; i++) {
let index = { ...normalizedDataSet };
if (numSet === index[i]['header']['set_no'] && numLine === index[i]['line']['line_no']) {
let shipMethods = JSON.parse('[{"id":103366,"name":"FREE Shipping"},{"id":200200,"name":"BEST"},{"id":555111,"name":"COLLECT"}]');
let shipMethod = shipMethods.filter(item => { return item.id === args.carrier_id }); // [0]['name'];
console.log("date_updated this index", i);
index[i]['order']['ship_details']['carrier_id'] = args.carrier_id;
index[i]['order']['ship_details']['method'] = shipMethod[0]['name'];
newNormal.push(index[i]); // Should update order.ship_details.carrier_id
} else {
console.log("Use original index");
newNormal.push(normalizedDataSet[i]); // Should NOT update order.ship_details.carrier_id
}
}
console.log('new normal', JSON.stringify(newNormal));
}
normalizeData(data, numSet, numLine, args);
I'm not sure how the property is getting assigned "before" a function is called that assigns it.
I'm guessing it may have something to do with the data destructuring, but I'm not certain.
Any guidance / help is greatly appreciated.
In this example I'm trying to update just { "setNo": 0, "lineNo": 1 } with new normal order data, but both lines 0 and 1 are being set.
for (var i = 0; i < featureSet.features.length; i++) {
for (var f = 0, f1 = featureTracts.length; f < f1; f++) {
rows["Sensor"] = featureTracts[f].attributes.Sensor;
rows["Resolution"] = featureTracts[f].attributes.Resolution;
rows["Dtofparse"] = featureTracts[f].attributes.Dtofparse;//PATH_ROW
// alert(rows);
}
resosat1[i] = rows;
}
i am trying to print all values in resosat1[i] array but it will take only last value and all values overwirite and update only last value to array
for (var i = 0; i < featureSet.features.length; i++) {
var rowAaaray = [];
for (var f = 0, f1 = featureTracts.length; f < f1; f++) {
var rows = {};
rows["Sensor"] = featureTracts[f].attributes.Sensor;
rows["Resolution"] = featureTracts[f].attributes.Resolution;
rows["Dtofparse"] = featureTracts[f].attributes.Dtofparse;//PATH_ROW
// alert(rows);
rowAaaray.push(rows);
}
resosat1[i] = rowAaaray;
}
}
Because you are maintaining one variable and overriding it in loop. So you will get last overwritten object only.
I agree with the guy in the comment. Try:
for (var i = 0; i < featureSet.features.length; i++) {
for (var f = 0, f1 = featureTracts.length; f < f1; f++) {
rows["Sensor"] = featureTracts[f].attributes.Sensor;
rows["Resolution"] = featureTracts[f].attributes.Resolution;
rows["Dtofparse"] = featureTracts[f].attributes.Dtofparse;//PATH_ROW
resosat1[f] = rows; <======== THIS WILL STORE THE VALUE OF EACH ROW CREATED
}
<==//TRY STORING THE resosat1 array In another array here instead.
//eg. arrayEx[i]=resosat1
//Alternatively, you could use a 2D Array eg. arrayEx[i][f]
}
Hope this helps you out.
try this one..
for (var i = 0; i < featureSet.features.length; i++) {
var arr = []; // create array
for (var f = 0, f1 = featureTracts.length; f < f1; f++) {
var rows = {};
rows["Sensor"] = featureTracts[f].attributes.Sensor;
rows["Resolution"] = featureTracts[f].attributes.Resolution;
rows["Dtofparse"] = featureTracts[f].attributes.Dtofparse;//PATH_ROW
// alert(rows);
arr.push(rows);
}
resosat1[i] = arr;
}
}
rows is undeclared (at least in your snippet).
On the other hand, putting var rows = {}, as some suggest, will fix your problem because it creates new object each time. But, if your javascript version accepts it, it would be better to declare it wit let because, this way, you will be really creating new fresh variable (in block scope).
Declaring rows in an outer block will not fix your problem because you will be assigning same object during the whole loop.
Can someone explain this to me?
This works:
function Pin() { };
function Pi() { };
function User() { };
var PiArray = [];
var PinArray;
for (var i = 0; i < 2; i++) {
PiArray[i] = new Pi();
PiArray[i].Name = '';
PiArray[i].PinArray = [];
for (var j = 0; j < 25; j++) {
PiArray[i].PinArray[j] = new Pin();
PiArray[i].PinArray[j].Number = j + 2;
PiArray[i].PinArray[j].PulseWidth = 0;
PiArray[i].PinArray[j].PulseFrenquency = 0;
PiArray[i].PinArray[j].Dirtybit = false;
};
}
/* Output is
[{"Name":"","PinArray":[{"Number":2,"PulseWidth":0,"PulseFrenquency":0,"Dirtybit":false},{"Number":3,"PulseWidth":0,"PulseFrenquency":0,"Dirtybit":false},{"Number":4,"PulseWidth":0,"PulseFrenquency":0,"Dirtybit":false},
etc.
*/
But I cannot figure out how to make this into an object, the scope of the variables do not behave as I expect.
this is what an instance of what I tried:
function Pin() { };
function Pi() { };
var User = (function () {
PiArray = [];
function User() {
var PinArray;
for (var i = 0; i < 2; i++) {
PiArray[i]= new Pi();
PiArray[i].Name = '';
PiArray[i].PinArray = [];
for (var j = 0; j < 25; j++) {
PiArray[i].PinArray[j] = new Pin();
PiArray[i].PinArray[j].Number = j + 2;
PiArray[i].PinArray[j].PulseWidth = 0;
PiArray[i].PinArray[j].PulseFrenquency = 0;
PiArray[i].PinArray[j].Dirtybit = false;
};
}
}
console.log(JSON.stringify(PiArray));
return User;
})();
new User();
and the output is:
[ ]
I don't understand why?
Your console.log(JSON.stringify(PiArray)); shows an empty array in the second case because at the time it runs, you've have not called the function User() yet. The IIFE just defines the function User() and then returns it. It does not actually call it.
Your later code new User() does call it, but that's after your console.log() has already executed.
Move the console.log() to the end of your User() function definition (but inside the function) and you will see the expected value.
function Pin() { };
function Pi() { };
var User = (function () {
PiArray = [];
function User() {
var PinArray;
for (var i = 0; i < 2; i++) {
PiArray[i]= new Pi();
PiArray[i].Name = '';
PiArray[i].PinArray = [];
for (var j = 0; j < 25; j++) {
PiArray[i].PinArray[j] = new Pin();
PiArray[i].PinArray[j].Number = j + 2;
PiArray[i].PinArray[j].PulseWidth = 0;
PiArray[i].PinArray[j].PulseFrenquency = 0;
PiArray[i].PinArray[j].Dirtybit = false;
};
}
console.log(JSON.stringify(PiArray));
}
return User;
})();
new User();
FYI, it is unclear what you are trying to accomplish with this structure because PiArray is only reachable from your constructor. Once the constructor has been called, no other code can reach it or use it. Plus all calls to the constructor will modify the same PiArray. PiArray in this context works like a class static (as the term is used in other languages). It's a common variable shared by all instances of the class, but not accessible outside the code for the object itself.
If you had other methods on the User object, then they could also access PiArray and it might make more sense to have it.
You can create an instance that has a different array stored in it like this:
var MyObj = function(data) {
// assign a copy of the passed-in array as instance data
// You don't have to make a copy - you could just assign in incoming array
this.data = data.slice(0);
}
var x = new MyObj([1,2,3]);
var y = new MyObj([9,8,7]);
console.log(x.data); // [1,2,3]
console.log(y.data); // [9,8,7]
This is probably an easy question but it's late at night and I can't get my head round this.
here's my code
$(document).ready(function () {
var items = getNumber();
for (var i = 0; i < items.length; i++) {
var test = items[i].action;
test();
}
});
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({ id: i, number: num, action: function () { alert(i) } });
}
return items
}
Could someone explain to me why the alert output is always 5? I want the alert parameter to be the index at the time it is added to the array. It seems like it is being dynamic.
If you could also post a solution how i could get this to work i would be extremely thankful
This is a common issue with JavaScript variable scoping: new variables are only introduced in a new execution context and thus, in the problematic code, i is shared across all the action callbacks.
Anyway, here is the corrected code following the standard idiom:
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
// _i is a new variable for each callback
action: (function (_i) {
// use separate (one per callback) _i variable
return function () { alert(_i) }
})(i) // pass in current value for loop
});
}
return items
}
Alternatively, if one doesn't like all the nesting, it's fine to use a "named" function to perform the same task. The key to point is that the closure is created (and returned from) a new execution context so that a different variable is closed-over:
function getNumber()
{
function mkAction (i) {
return function () { alert(i) }
}
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
action: mkAction(i)
});
}
return items
}
Another approach is to use Function.bind from ES5:
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
action: (function (_i) { alert(_i) }).bind(null, i)
});
}
return items
}
(Note that Function.bind can be emulated using a new execution context/closure even without native browser support. See the MDC documentation.)
See also:
JavaScript closure inside loops – simple practical example
Passing functions to setTimeout in a loop: always the last value?
How do JavaScript closures work?
I have a for loop that needs to return something on every iteration:
for(var i=0;i<100;++i) {
return i;
}
but return breaks the loop. How can I return but kee the loop running?
Store it inside an array.
var array = [];
for (var i = 0; i < 100; ++i) {
array.push(i);
}
The context here is unclear. If you are trying to execute a function for each iteration of the loop, why not something simple like calling a function from within the loop?
for(var i=0;i<100;++i) {
processIteration(i)
}
In processIteration you could simply handle what you need to happen with that value.
Store the values you need to return in an array, then after the loop, return the array.
There are 3 ways to solve this
Promises
function loop() {
promises = []
for (var i = 0; i < 100; ++i) {
// push a promise resolve to a promises array
promises[i] = Promise.resolve(i);
}
return promises;
}
// Observe the promises loop
for (let p of loop()) {
p.then(console.log)
}
Callbacks
function loop(cb) {
for(var i = 0; i < 100; ++i) {
// calling the callback
cb(i);
}
}
// Pass a do something method
// Here it's the console log as the callback
loop(console.log)
Yield
// Generator function for loop over 100
function* loop() {
for (var i = 0; i < 100; ++i) {
// return value from loop
yield i;
}
}
// Initialize the generator function
let it = loop();
// Call and get the resulr
// it.next().value
var result = it.next();
while (!result.done) {
console.log(result.value); // 1 2 3 .... 99
result = it.next();
}