Two identical functions one works one does not - javascript

I created two functions, GOODself and BADself, called in succession to debug a problem I have in a larger script illustrated here. I can't figure out why BADself stalls at the line aryVarAbi[0] = 5;.
If I call it first it still happens. According to the console in Firefox aryVarAbi is not defined.
GAB = GOODself(0, 4, 1);
GAB = BADself(0, 4, 1);
function GOODself(GABin, nCols, nRows) {
var aCol = 0;
var aryVarABi = [1,1,1,1];
for (aCol=0; aCol < nCols - 1; aCol++) {
alert("GOOD1 " + aryVarABi[aCol]);
aryVarABi[0]= 5;
alert("GOOD2 " + aryVarABi[aCol]);
} // for aCol
return (aryVarABi[0]);
} // GOODself
function BADself(GABin, nCols, nRows) {
var aCol = 0;
var aryVarABi = [1,1,1,1];
for (aCol=0; aCol < nCols - 1; aCol++) {
alert("BAD1 " + aryVarABi[aCol]);
aryVarAbi[0] = 5;
alert("BAD2 " + aryVarABi[aCol]);
} // for aCol
return (aryVarABi[0]);
} // BADself

JavaScript is case senstive. You've defined var aryVarABi = [1,1,1,1];. Notice the capital B. You're referring to aryVarAbi[0] = 5;. Notice the lowercase b.

I think you want aryVarABi[0] = 5; as opposed to aryVarAbi[0] = 5;
The 'b' in the latter is lowercase.

Javascript variables are case sensitive, so aryVarABi is a different variable from aryVarAbi.
Please change the line aryVarAbi[0] = 5; to aryVarABi[0] = 5;.

Related

Javascript: Dynamic Variables in For Loop

I am a javascript beginner and need your help! Thanks a lot for any help!
cell_660 = cell_638;
cell_659 = cell_637;
...
It worked that way. I now want to do this every second for all 660 variables to change their value to the value of the variable which name has the number (own number -22) at the end. Of course without writing 660 lines of code! I tried this so far:
var count = 660;
setInterval(function(){
for(var i=1;i<=660;i++){
'cell_' + count = 'cell_' + eval(count - 22);
count--;
}
count=660;
},1000);
How do I write this correctly? I already read about window['cell_' + count] - but I don't want to create 660 new variables every second. I want to CHANGE the value of 660 Variables every second.
Do you need to change 660 variables every second? What if you just create one numeric variable which keeps the location of "where in the array to start" when you display or use the array values?
var cells = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var currentStart = 0;
// create an interval to modify currentStart
setInterval(function () {
currentStart = (currentStart + 22) % cells.length;
}, 1000);
function doSomething() {
// display contents starting at currentStart
var msg = "";
for (var i = 0; i < cells.length; i++) {
var index = (i + currentStart) % cells.length;
// do something with cells[index]
msg += "," + cells[index];
}
console.log(msg);
}
document.querySelector("#thing").addEventListener("click", doSomething);
<button id='thing'>click me</button>
with an array
how about having an array instead of this many variables ?
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
function moveArrElem() {
// loop all elements of the array
// using arr.map give us a buffer so current index are keeped while doing the modification
arr = arr.map((_, i) => {
// get the new index and make it valid if necessary
let newIndex = i - 2;
if (newIndex < 0) {
newIndex += arr.length
}
return arr[newIndex]
})
console.log(arr)
}
console.log(arr)
setInterval(moveArrElem, 2000)
about window['cell_' + count] it doesn't create a new variable each time, in fact var test = 42 is equal to window["test"] = 42 if you're in the global scope (outside of any functions and other blocks)
so window['cell_' + count] will just modify the value of the var
var test = 42
console.log(window["test"])
finally try to avoid eval as much as you can, it is slow and generally a security issue
some (I'm of these) a call to eval is almost always sign ther is a misconception elsewhere
without array
since OP told in comment he still hasn't learned array, here's a solution without array
let quantity = 660
// declaring the 660 vars
for (let i = 0; i < quantity; i++) {
window["cell_" + i] = i;
}
function moveCells() {
// need some tmp vars
for (let i = 0; i < quantity; i++) {
window["tmp_" + i] = window["cell_" + i];
}
for (let i = 0; i < quantity; i++) {
let newIndex = i - 22
if (newIndex < 0) {
// equals to : newIndex = newIndex + quantity
newIndex += quantity
}
window["cell_" + newIndex] = window["tmp_" + i];
}
// displaying 660 items would take to much time and place
console.log("cell_42 : " + cell_42)
console.log("cell_43 : " + cell_43)
console.log("cell_44 : " + cell_44)
console.log("cell_45 : " + cell_45)
console.log("cell_46 : " + cell_46)
}
console.log("cell_42 : " + cell_42)
console.log("cell_43 : " + cell_43)
console.log("cell_44 : " + cell_44)
console.log("cell_45 : " + cell_45)
console.log("cell_46 : " + cell_46)
setInterval(moveCells, 1000)
Before I give you an answer, I'd first like to point out this is terrible code practice. You should never need 660 variables! Whatever you're trying to do could probably be accomplished with arrays. That being said, here is how you would make this work, and how you should actually do this below. I strongly recommend that you consider going with the array method!
setInterval(function() {
for(var i = 660; i > 22; i--) {
window['cell_' + i] = window['cell_' + (i - 22)];
}
},1000);
Now here is something more along the lines of what you should actually be doing.
var cells = [/* 660 elements */];
setTimeout(function() {
for(var i = 22; i < 660; i++) {
cells[i] = cells[i - 22];
}
}, 1000);
In fact, with this method, you can do the whole thing in one line with the new Array#copyWithin method in ES6.
const cells = [/* 660 elements */];
setTimeout(() => {
cells.copyWithin(22);
}, 1000);

javascript loop through messages

I have 3 messages in variables.
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
I am trying to create a function that when i click it the first time it console.log(msg1), when i click it the second time it console.log(msg2), 3rd time console.log(msg3), 4th time console.log(msg1) and 5th msg2 etc.
$scope.clickMsg = function () {
console.log(msg1);
}
i've tried loops, timers etc but i could not make it work.
Does anyone know how to do this?
Use an array instead, and it's a bit easier, you'd just increment a number on each click, and use that number to select the item from the array
var msg = [
"hello1",
"hello2",
"hello3"
];
var i = 0;
var $scope = {};
$scope.clickMsg = function () {
console.log( msg[i] );
i++; // increment
if (i === msg.length) i = 0; // reset when end is reached
}
document.getElementById('test').addEventListener('click', $scope.clickMsg)
<button id="test">Click</button>
ES6 Generators based version:
var messages = (function*() {
for(;;) { yield msg1; yield msg2; yield msg3; }
})()
$scope.clickMsg = function () {
console.log(messages.next().value);
}
Unlike other answers, does not require you to use a different datatype and will also work for the locally scoped variables (i.e. non-window scoped variables).
Try It Online !
There are a few ways to do this in terms of accessing the string, I'd recommend putting them into an array rather than accessing the global/scoped object but it's up to you. Anyway on to the code.
var messagesArray = ["hello1", "hello2", "hello3"];
var messagesObject = {
msg1: "hello1",
msg2: "hello2",
msg3: "hello3"
}
var counter = 0;
function LogMessage() {
console.log(messagesArray[counter % 3]);
console.log(messagesObject["msg" + (counter % 3 + 1)]);
counter++
}
<button onclick="LogMessage()">Click Me</button>
Simply use with increment value like this
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
var c = 1;
$scope.clickMsg = function () {
c = c > 3 ? 1 : c;
console.log(window['msg'+c])
c++;
}
Working snippet
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
var c = 1;
var $scope={} //for testing
$scope.clickMsg = function () {
c = c > 3 ? 1 : c;
console.log(window['msg'+c])
c++;
}
function check(){ //for testing
$scope.clickMsg();
}
<button onclick="check()">click</button>
The alternative is using scopes, defining them as
this["msg"+i] = "some stuff";
and retrieving them as
this.msg0;
just do something like this, will work for you, make sure you reset it back if needed or do something, otherwise after first loop, you get undefined:
var msgs = ["hello1","hello2","hello3"], i=0;
$scope.clickMsg = function() { //angular $scope for example
console.log(msgs[i]);
if(i < msgs.length-1) {
i++;
} else {
i=0; //reset the loop
}
}

What's the difference between angular.equals and _.isEqual?

I mean is there any difference in performance? Which one is able to make the best deep comparison? Sometimes angular's equals function is not able to find every difference.
I have also noticed, that the angular version of this function is not checking the '$$hashKey' key.
They basically act the same by comparing the values itself and all inner properties. Performance is also close to being the same, at least this will be a difference in 100-200 ms for 10000 elements. I have created small tests suite, warning: your browser page will freeze for few seconds when you run code snippet. I'm not totally sure is this correct way to measure performance so feel free to suggest better ways.
angular
.module("comparsion", [])
.controller("ComparsionCtrl", function($scope) {
var testCases = 10000;
console.time("underscore");
for(var i = 0; i < testCases; i++) {
var obj = createRandomObj(5, true);
var obj1 = createRandomObj(5, true);
_.isEqual(obj, obj1);
}
console.timeEnd("underscore");
console.time("angular");
for(var i = 0; i < testCases; i++) {
var obj = createRandomObj(5, true);
var obj1 = createRandomObj(5, true);
angular.equals(obj, obj1);
}
console.timeEnd("angular");
// Random object generator from http://stackoverflow.com/questions/2443901/random-object-generator-in-javascript
function createRandomObj(fieldCount, allowNested)
{
var generatedObj = {};
for(var i = 0; i < fieldCount; i++) {
var generatedObjField;
switch(randomInt(allowNested ? 6 : 5)) {
case 0:
generatedObjField = randomInt(1000);
break;
case 1:
generatedObjField = Math.random();
break;
case 2:
generatedObjField = Math.random() < 0.5 ? true : false;
break;
case 3:
generatedObjField = randomString(randomInt(4) + 4);
break;
case 4:
generatedObjField = null;
break;
case 5:
generatedObjField = createRandomObj(fieldCount, allowNested);
break;
}
generatedObj[randomString(8)] = generatedObjField;
}
return generatedObj;
}
// helper functions
function randomInt(rightBound)
{
return Math.floor(Math.random() * rightBound);
}
function randomString(size)
{
var alphaChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var generatedString = '';
for(var i = 0; i < size; i++) {
generatedString += alphaChars[randomInt(alphaChars.length)];
}
return generatedString;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js"></script>
<div ng-app="comparsion">
<div ng-controller="ComparsionCtrl"></div>
</div>
angular.equals:this is angular equals comparision.
_.isEqual:this is underscore equal functionality.you need to import underscore js before using this.

Having Trouble Understanding Javascript Methods

This is my current assignment :
Add a method that will increase the value of one of the numeric properties.
Add a method that will decrease the value of the same numeric property.
Create a for loop after creating an instance of the character. The loop will iterate 100 times.
Inside the loop call one of the methods based on a random number from zero to 3. Using a switch statement, if the value is 0 then call the method that losses; 1 don’t call anything; 2 call the method that gains.
Here is my current coding. I know I'm doing something wrong. I just can't figure out what I am doing wrong with the switch statement.
var BR = "<br />";
function person(name, sandwiches) {
this.name = name;
this.sandwiches = sandwiches;
function jump() {
var text = " leaps over an obstacle.";
return fname + text;
}
function run() {
var text = " runs as fast as they can";
return fname + text;
}
function dodge() {
var attack = math.random();
var att = math.round(attack);
var defense = math.random();
var def = math.round(defense);
if(att > def) {
return "You missed";
}
else {
return "You dodged";
}
}
function date() {
var today = new Date();
return today.toDateString();
}
function shout() {
var word = "Oh no";
return word.toUpperCase();
}
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
this.loseSandwich = function (sandwiches) {
sandwiches = sandwiches - 1;
return sandwiches;
};
}
var character = new person("Jerry", 1);
for(i=0; i < 100; i++) {
var random = Math.floor(Math.random() * 3);
switch(random) {
case 0:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
break;
case 1:
break;
case 2:
character.addSandwich(character.sandwiches);
break;
}
}
document.write("Name: " + character.name + BR);
document.write("Sandwiches: " + character.sandwiches + BR);
Math.floor(Math.random() * 3) is not what you want.
You want something like Math.random() % 3 to get 0, 1, or 2 every single time
Not sure if this is your problem, but it is at least one of them;
In a few places you have a lowercase math, for example:
function dodge() {
var attack = math.random();
JavaScript is case-sensitive, and it should be Math.random() not math.random()
Another issue is that these functions:
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
do not change the number of sandwiches. You get in a value of sandwiches, add or subtract 1, then return that changed number, but never use the returned result.
You are only changing the value of the variable that was passed in, not changing the number of sandwiches on the instance of the person.
Note that this.sandwiches (the variable on the instance of a person) is not the same variable as sandwiches (the function argument)
I dont think there is any reason to pass the number of sandwiches into those functions, and they could just do:
this.addSandwich = function () {
this.sandwiches = this.sandwiches + 1;
};
or more simply:
this.addSandwich = function () {
this.sandwiches++;
};
Another problem here:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
The console.log statement is trying to log sandwiches but that is not a variable at that point. You probably wanted console.log(character.sandwiches); However this wouldn't cause an exception, it would just always log undefined.

Can we pass variables by reference in JavaScript Function?

I am calculating row and column of a given point by javascript function.
To achieve this I have to declare global variables
var global_row;
var global_col;
Here is function body
function calculate_city_row_col(cur_city_id)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
//Saving Result in seperate row and column
global_row = r + 1; //Global Variable
global_col = c + (cur_city_id - (max_city_id + 1)); //Global Variable
}
Here is function call
var city_id = 1244;
calculate_city_row_col(city_id);
var city_row = global_row;
var city_col = global_col;
Is there anyway to directly pass local variables? (without using global variables)
like this
calculate_city_row_col(cur_city_id, city_row_ref, city_col_ref);
Just return an object:
function calculate_city_row_col(cur_city_id)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
return {
row: r + 1,
col: c + (cur_city_id - (max_city_id + 1))
};
}
var rowAndCol = calculate_city_row_col(1244);
var city_row = rowAndCol.row;
var city_col = rowAndCol.col;
Can we pass variables by reference in JavaScript Function
No. JavaScript is purely pass-by-value (the value passed when you pass an object around is an object reference, but it's still a value).
Your options are:
Have the function return an object (or array)
function calculate_city_row_col(cur_city_id)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
//Saving Result in seperate row and column
return {
row: r + 1,
col: c + (cur_city_id - (max_city_id + 1))
};
}
Usage:
var result = calculate_city_row_col(someCityId);
console.log(result.row);
console.log(result.col);
Have the function accept a reference to an object (or array) that it updates
function calculate_city_row_col(cur_city_id, result)
{
var r = 565;
var c = 1;
var max_city_id = 159895;
do{
if((r%2) == 0) c++;
max_city_id -= r;
r--;
}
while(cur_city_id <= max_city_id)
//Saving Result in seperate row and column
result.row = r + 1;
result.col = c + (cur_city_id - (max_city_id + 1));
}
Usage:
var result = {};
calculate_city_row_col(someCityId);
console.log(result.row);
console.log(result.col);
Barring a strong reason to go with #2 in a specific situation, #1 is usually the best option. For instance, if you were calling this function thousands of times in a tight loop, there might be a justification for reusing a single object (by passing it in) instead of creating a new object every time.

Categories