Javascript Objects and variable scope - javascript

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]

Related

in JS I Don't Know this Expression

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]();

How array index is getting assigned before it is pushed to new array

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 loop prints only last value array in javascript

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.

Setting functions to onclick for Buttons within loops with strings in HTML/Javascript

var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
var NewButton = document.createElement("NewButton");
var IdString = "ID" + i + "_" +j;
NewButton.onclick = function() { DoStuff(IdString) };
RelevantDiv.appendChild(NewButton);
}
}
function DoStuff(IdForStuff) {
// Does stuff with id
}
The problem is that every time the NewButton.onclick is set, that it is setting it to the final IdString which is "ID4_4".
Worth noting, that you won't have such problems if you use let or constinstead of var:
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 5; j++) {
const NewButton = document.createElement("NewButton");
const IdString = "ID" + i + "_" +j;
NewButton.onclick = function() { DoStuff(IdString) };
RelevantDiv.appendChild(NewButton);
}
}
Your underlying issue is that the variable being used within the onclick callback, IdString, is having its declaration hoisted to the top of the current scope, ie the function it's running within. That means that every time you're within the loop, its value is overwritten - it's functionally the same as this:
var IdString;
var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
var NewButton = document.createElement("NewButton");
IdString = "ID" + i + "_" +j;
NewButton.onclick = function() { DoStuff(IdString) };
RelevantDiv.appendChild(NewButton);
}
}
You need to ensure that you capture the right value of IdString when you need it, which is typically done through the use of a closure:
var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
(function(IdString) {
var NewButton = document.createElement("NewButton");
NewButton.onclick = function() { DoStuff(IdString) };
RelevantDiv.appendChild(NewButton);
})("ID" + i + "_" +j)
}
}
Here we create another inner function to create a new scope to hold each individual IdString value. It's then immediately called with the right value for each iteration of the loops. IdString is then captured within this closure, and the correct value will be used within the onclick callback.
Alternatively, you can bind the argument at the moment you know what the relevant value is:
var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
var NewButton = document.createElement("NewButton");
NewButton.onclick = DoStuff.bind(null, "ID" + i + "_" +j);
RelevantDiv.appendChild(NewButton);
}
}
This does away with both of the inner functions, and directly assigns the onclick event to a copy of the DoStuff function that will have the right argument.
The problem here is that, when the handler you assign runs, the loop has already looped through all iterations, and the variable at that point will be at its final state. To avoid this, you need to use a lock. It involves a self-executing function (function () { // code })() which saves the current state of the variable. When the variable in the current iteration, for example State 2 is given as an argument to the self-executing function, the scope of the function will save this state. When the for loop continues, the original variable will still change, but the scope of the new "inner function" will keep the value "locked". So even when the loop-variable will in the end be at its 4th state, the locked variable will still be in state 2.
for (var i = 0; i < 5; i++) {
button.addEventListener ("click", function () {
// Here, i would normally always be 5
(function (lockedIndex) {
// This lock will make i the way it should be
// You have to use lockedIndex instead of i
})(i)
});
}
For your code, this would look something like:
var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
(function (ix, jx) {
var NewButton = document.createElement("NewButton");
var IdString = "ID" + ix + "_" +jx;
NewButton.onclick = function() { DoStuff(IdString) };
RelevantDiv.appendChild(NewButton);
})(i, j)
}
}
function DoStuff(IdForStuff) {
// Does stuff with id
}

Array appending after each onclick and loop in javascript

This is the code fragment I have tried:
radio.onclick = function() {
var pp = e.target.result.split("\n");
var pq = pp.split('\n');
var pr = []; // array to append each values
for (var k = 0; k < pq.length; k++) {
var a = pq[0];
}
pr = a; // I need to create an array which should append again and again
}
In this code, after clicking a radio, a loop generates the value for the 'a' variable, whom it's added to array 'pr'. I want to add the generated value to 'pr' itself after the next on-click.
Is it possible?
Just define the array
pr
globally.
var pr = []; // array to append each values
radio.onclick = function() {
var pq = pp.split('\n');
for (var k = 0; k < pq.length; k++) {
var a = pq[0];
}
pr.push(a); // i need to create an array which should append again and again
}
But there you just get the last pq[0]of the loop
Hope that helps
You probably want to do this:
radio.onclick = function() {
var pq = pp.split('\n');
var pr = []; // array to append each values
for (var k = 0; k < pq.length; k++) {
pr.push(pq[k]);
}
}
If you need global access to pr just define it outside from radio.onclick.
Edit
even shorter:
radio.onclick = function() {
var pq = pp.split('\n');
}
or global
var pq = [];
radio.onclick = function() {
pq = pp.split('\n');
}
$(document).ready(function(){var array = new Array(); //Global declaration
radio.onclick = function(){
//do stuff here..
//get your value
array.push(your value);
}
});
//if you want to clear the array
array.splice();

Categories

Resources