Adobe javascript object undefined after function - javascript

I'm trying to learn some javascript by making a script for adobe after effects cs6. However i got stuck and can't figure out why. Let me explain my problem.
at row 156, in the doMath function is where my problems start. I can't figure out why the copyarray makes the layers variable undefined. it's not only the copyarray function that makes the variable undefined. The getSmallest and the getLargest does it aswell.
Some data from my code that i printed out (Might be useful).
Layername +Y max="80" target="4" inverted
axis Y
maxValue 80
target 4
positive true
inverted true
http://pastebin.com/tWQs4mf8 <--- my code
function doMath(layers){
for(i=0;i!=layers.length;i++)
{
if(layers[i].axis=="X")
{
layers[i].convertedData=layers[i].Xdata;
}
else
{
layers[i].convertedData=layers[i].Ydata;
}
alert(layers[i]) //Shows on the alert "Object object"
var copy = copyArray (layers[i].convertedData);
alert(layers[i]); //Shows undefined
var smallest = getSmallest(copy);
var largest = getLargest (copy);
var range = largest-smallest;
$.writeln(smallest + " " + " " + largest + " " + range);
if(layers[i].Positive==null)
{
var temp = getConverted(layers[i].convertedData,smallest,range,layers[i].maxValue,layers[i].inverted);
layers[i].convertedData=temp;
}
}
};
function copyArray(a){
var b = [a.length];
for(i=0;i!=a.length;i++)
{
b[i] = a[i];
}
return b;
}
Since i'm very new to javascript a simple reason what's happening is very appreciated.

It's not making layers undefined, it's making layers[i] undefined.
The problem is that you're using the global variable i in both loops. So when copyArray is done, i is set to layers.length. But the last element in layers is layers[layers.length-1].
You should always use local variables, not global variables, unless you have a good reason to need the data to be visible in multiple functions. So you should write:
for (var i = 0; i < a.length; i++)
in your loops.

Related

Having trouble understanding what is going on in code

Here is some code I'm really having issues understanding (JavaScript)
function func(x) {
var y = x + 2;
z = 20;
return function(y) {
var z = y * 3;
return function(z) {
return x + y + z;
};
};
}
console.log(func(3)(4)("z"));
output: 7z
I have a lot of experience with Java (only Java) and I'm really having issues understanding how JavaScript works.
I tried debugging and going step by step over code but I'm still very confused.
One sub-question I have is whether y on line 2 is the same y as in
return function(y) line.
Any help would be greatly appreciated!
When looking for value of variable, JS will pick it from the closest scope going upwards.
In line 5, the y is the y from the argument and not from the upper scope. That value although is enclosed (read closures), is not being used here.
Same, goes for the z below.
When running the statement return x + y + z; the outer scope (that is shadowing the variable y) is destroyed. So the other closes values are used ergo 3 and 4.
function func(x) {
var y = x + 2;
z = 20;
return function(y) {
var z = y * 3;
return function(z) {
return x + y + z;
};
};
}
console.log(func(3)(4)("z"));
Get yourself a good code editor for JS (vscode is great and free)
Go to a variable, press F2 and give it a more unique name.
check which occurrences are affected.
"use strict"! what is Strict Mode?
This is what your code then might look like.
"use strict";
function func(arg0) {
var var1 = arg0 + 2;
// undeclared/global variable
z = 20;
return function (arg2) {
var var2 = arg2 * 3;
return function (arg4) {
return arg0 + arg2 + arg4;
};
};
}
console.log(func(3)(4)("z"));
I think this makes it clearer what variable/parameter is what.
And if you run this, you'll get an error regarding your usage of the undeclared variable z, because strict mode doesn't allow this, whereas sloppy mode would create/use a global variable.
Sidenote: Take a look at Typescript. Coming from such a strict language like Java you might prefer the ability to type your code.
What I understand is from this function call is
fun(3)(4)("Z");
first call
x = 3;
y = 5;
z = 20;
second call
y=4;
z=60;
x=3;
third call
x=3; // from first function parameter
y=4; // y value from second function parameter
z="z" // third function parameter
In the it will return
3+4+"Z" = 7z
as string
All pre calculated values are useless
var is function scope, which means if you redeclare a variable in a function, it will be inside that function. It won’t mutate the outer scopes or global scopes same-named variable.
variableA = 16;
function incrementOne (localVariable) {
var variableA = localVariable + 1;
console.log("variableA internal", variableA);
}
incrementOne(10);
console.log("variableA", variableA);
And my request is not to use any syntax in js like this
variable = 16;
better use var if u really don't want to use let or cons.
var variable = 16
I can assure this that let and const will resolve your maximum understandings. Thanks.

Trouble with closure in Javascript loop

The process: In the game I'm making, there's a for loop that's supposed to save a value in an array. That value changes with each iteration. The problem: when the loop is done running, every element of the array is identical, all showing the most recent value.
I know this issue is common, and I've made so many different tweaks and attempts at solving it over the past 2 days.
0) I tried separating things into separate functions as much as possible.
1) I tried defining my loop counters with "let" so they would have a local scope.
2) I tried wrapping my assignment in a self-executing function so it would happen immediately, preserving the value of currentlyOn before the next loop iteration changes it. My counter is the variable c.
(function(c2, currentlyOn2) {
onAtSameTime[c2] = currentlyOn2;
return 0;
})(c, currentlyOn);
3) I tried attempt #2 with the added feature of returning a function, which still didn't save the value of currentlyOn. This option isn't a good one for me anyway, because the whole point is that I'm doing some computations ahead of time so my game will have a quick animation loop.
onAtSameTime[c] = (function(currentlyOn2) {
return function() {
return currentlyOn2;
};
})(currentlyOn);
I'm tired of beating my head against this wall. Can anyone explain what I'm doing wrong?
For more details, check out the jsfiddle I made. The problem area is at line 59, using a simple assignment:
onAtSameTime[c] = currentlyOn;
onAtSameTime[c] = currentlyOn; sets onAtSameTime[c] equal to the reference of currentlyOn, since currentlyOn is an array, not a primitive value. That reference gets updated with each iteration. You could work around that by creating a copy of the array before adding it to the onAtSameTime array. Something like onAtSameTime[c] = [].concat(currentlyOn); would do the trick.
See this fork of your JSFiddle: https://jsfiddle.net/L2by787y/
You could make a copy from currentlyOn for assigning to onAtSameTime[c]. This keeps the values, but does not keep the reference to the same array.
onAtSameTime[c] = currentlyOn.slice(); // use copy
"use strict";
function log(text) {
document.getElementById("logbox").innerHTML += JSON.stringify(text) + "<br>";
return 0;
}
function whichSwitchesAreOn() {
var currentlyOn = [],
flickedSet,
flickedOne,
turningOnCheck;
for (var c = 0; c < switchesToggled.length; c++) {
flickedSet = switchesToggled[c];
for (var d = 0; d < flickedSet.length; d++) {
flickedOne = flickedSet[d];
turningOnCheck = currentlyOn.indexOf(flickedOne);
if (turningOnCheck == -1) {
currentlyOn.push(flickedOne);
} else {
currentlyOn.splice(turningOnCheck, 1);
}
}
log("currentlyOn: " + currentlyOn);
onAtSameTime[c] = currentlyOn.slice(); // use copy
}
return 0;
}
var switchesToggled = [[0], [1, 2], [0], [2], []],
onAtSameTime = [];
whichSwitchesAreOn();
log(onAtSameTime);
<div id="logbox"></div>
You say you have tried let?
Did you have let currentlyOn = [] inside of the for loop?
for(var c = 0; c < switchesToggled.length; c++) {
let currentlyOn = [];

Why is my Javascript logging Unlogged values to the CodeCademy Console?

This has happened many times and I've just ignored it until now, however it's bugging me because I'm not sure if my code will be correct.
The issue is that when I console.log(TextA) or (TextB) and then put a value into a variable, the console will log the value that I push to the variable.
Example below:
My CodeCademy code is:
var slaying = true;
var youHit = (Math.floor(Math.random() * 2) == 1);
var damageThisRound = Math.floor(Math.random()*5 + 1);
var totalDamage = 0;
while (slaying) {
if (youHit) {
console.log("Congrats, you hit");
} else {
console.log("You were defeated by the dragon");
}
slaying = false;
}
And my console log is:
Congrats, you hit
false
Does this happen to anyone else? is it just an error with the CodeCademy system or is my Javascript not correct?
This is because their interpreter, much like the browser console, evaluates all of the code you put into it and all operations in javascript have a return value. Try this for example:
var y = (foo = 'x');
console.log(y);
The assignment operation has a return value. This becomes more apparent when you use things like eval and new Function to evaluate code, because they will show you the value of the last interpreted line of code, then you see that even do..while statements have a return value. If you change the last line of your while statement, you will see that the last value is logged instead of false.
Here is another example using eval that might demonstrate better:
eval('var foo = 0; i = 0; while( i < 2 ) { i++; foo = i * 9; } ')
Note that I didn't log anything explicitly there, but because foo = i * 9 (where i = 2) was the last line evaluated, you will see 18 in your console. Also note that if I had included var in that statement, you would see 1 instead, because i++ would be the last operation that returned a value (to add to the confusion, var assignments return undefined).

Javascript Object scope

This is a simplification of something that I've come up against in a larger project so I hope it makes sense.
I have two Objects:
FirstObj = {
data : [],
init : function()
{
for(var a = 0; a < 20; a++)
{
this.data[a] = 1;
}
}
};
SecondObj = {
init : function()
{
var cell = FirstObj.data[0];
cell = 0;
}
};
I then call the two init methods and log the results:
(function(){
FirstObj.init();
SecondObj.init();
console.log(FirstObj.data);
})()
Now, I was assuming - based on my basis in Actionscript - that the log would show an Array in which the first item is a 0 and the rest all 1 but the 0 does not seem to stick.
Why does the assignment of the 0 value not succeed here and yet works fine if, instead of cell = 0 I target directly at FirstObj.data[0] = 0.
I'm guessing this is a scope thing and I can work round it but I'm trying to get a proper understanding of how JS actually handles this stuff, especially when lumping code into Objects like this (as an aside, is this a good approach in peoples general opinion?).
Thank for any help.
Numbers in JavaScript are something called primitive value types (alongside strings, booleans null and undefined).
This means, that when you do
var cell = FirstObj.data[0];
You're passing the value in FirstObj.data[0] and not a refernece to it.
What you're doing is like:
var x = 5;
var y = x; // y is now 5
y = 4; // y is 4, x is still 5.
Of course, something like FirstObj.data[0] = 0 should work.
Array indexing returns values in Javascript, not references. It means that once data[0] is assigned to cell, further modification of cell will not affect data[0].
Assigning the array itself would result in the behavior you're looking for:
SecondObj = {
init : function()
{
var cells = FirstObj.data;
cells[0] = 0; // Will also affect data[0].
}
};

Initializing JavaScript array based on user input

I have an applet that allows the user to define values for 10 variables, all of which could be arrays. I then want the program to iterate over all possible combinations and then save the calculations to a variable.
Previously I hard-coded it to initialize the result array, SIGMA, by looping over every variable, regardless of if it is a vector or a single value, IE:
SIGMA = new Array(A.length);
for (i1=0; i1<A.length; i1++) {
SIGMA[i1] = new Array(B.length);
for (i2=0; i2<B.length; i2++) {
SIGMA[i1][i2] = new Array(C.length);
for (i3=0; i3<C.length; i3++) {
...
}
}
}
This results in a 10-dimensional SIGMA array, which makes processing really slow if a few or more variables are arrays.
What I'd like to do is to have it initialize SIGMA only for those variables that are an array and not a singular value. Therefore, if all variables are a single number except for two, say X and Y, then I'd want to have:
SIGMA = new Array(X.length);
for (i1=0; i1<X.length; i1++) {
SIGMA[i1] = new Array(Y.length);
}
However, I'm not quite sure how the best way to do this would be, as the number of for loops would depend on the number of variables that are arrays. I'm thinking I either need to use a recursive function or somehow incorporate a while loop.
Anybody have any good ideas on how this can be done? Thanks!
I was able to solve this problem by making a recursive function that included the for loops:
sigma = new Array(eval(var_idx[0]).length);
sigma_forloop('sigma', 0)
function sigma_forloop(X, idx) {
for (var i=0; i<eval(var_idx[idx]).length; i++) {
eval(X + '[' + i + ']' + ' = new Array(eval(var_idx[idx+1]).length);')
if (idx+2 < var_idx.length) {
var Y = X + '[' + i + ']';
sigma_forloop(Y, idx+1);
}
}
}
The variable 'var_idx' in an array of strings containing the variables that have more than one value, therefore, it's those variables that I want to loop over.
I'm sure there's an easier way of doing it, but this works for now.

Categories