-1

I see this question has come up a few times on here, but mine is a bit different. I'm new to JavaScript this is a basic program to show the problem.

var iterations = 0;

function someFunc(x, y, z) {

    for (var i=0; i<4; i++) {
        x[i] = x[i] * 2;
        y[i] = y[i] * 2;
        z[i] = z[i] * 2;
    }

    iterations++;

    if (iterations >= 10)
        return {done:true, x, y, z};
    else
        return {done:false, x, y, z};

}

function main() {

    var x = [0, 0, 0, 0];
    var y = [1, 1, 1, 1];
    var z = [2, 2, 2, 2];


    done = false;
    while (!done) {

        let {done, x, y, z} = someFunc(x, y, z);
        console.log(x, y, z);

        // Do some other stuff with x,y,z here,
        // like calling anotherFunc(x, y, z)

    }
}


main();

I get an error on the line with the call to someFunc. The error is "Exception Occurred: Reference error: x is not defined".

So what I'm doing is calling a function to update some arrays each time around a loop. I need to be able to get those arrays back out from the function called 'someFunc' so that I can pass them to another function to do some other work on them.

Then I need to feed them back into the first function again... and so on around and around the loop until I have finished.

I'm coming from Python where calls like

a, b, c = someFunc(a, b, c) 

are fine.

But I have no idea how to proceed with JavaScript. Any help would be much appreciated. Happy to clarify if my question is not totally clear.

davo36
  • 694
  • 9
  • 19
  • Why are you immediately reassigning the passed arguments? – Andrew Li Mar 05 '17 at 06:23
  • One thing worth noting is that in the second function you scope the `x, y, z` variables to the function by declaring with a `var`, but in the first function you omit the `var` when declaring `x, y, z` -- effectively casting them to the global scope. This may not be related to your problem, but unless it is your intention for these to be available in the global namespace it would be recommended to prefix them with `var` in the first function. – Alexander Nied Mar 05 '17 at 06:29
  • @Andrew Li: Because they have been altered in SomeFunc and I need the values back out... – davo36 Mar 05 '17 at 06:33
  • @davo36 That's kind of pointless. Why use arguments then if they won't be used? – Andrew Li Mar 05 '17 at 06:34
  • @Andrew Li: This is a toy example, I'm trying to show that someFunc takes in the arguments and alters them. I've edited the example. So the arguments are used. – davo36 Mar 05 '17 at 06:39
  • @anied: Sorry my example wasn't clear. I am not trying to declare those variables in the first function. I was passing them as arguments and altering them inside the function. I have edited my example. – davo36 Mar 05 '17 at 06:41
  • See http://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6 - `let` is block scoped in JS. Thus, it exists inside your while block and is hoisted, but its not initialized and throws the reference error. – Andrew Li Mar 05 '17 at 06:54

2 Answers2

0

Set value of function to an identifier, then use destructuring assignment to set properties globally and get properties.

let props = someFunc(x, y, z);
({done, x, y, z} = props);
console.log(x, y, z);
guest271314
  • 1
  • 15
  • 104
  • 177
  • FYI this works because you aren't redeclaring with let and thus they aren't being blocked scoped, and aren't uninitialized when you try to access it. This reassigns the existing function scoped var variables. – Andrew Li Mar 05 '17 at 07:03
  • @AndrewLi OP shouldn't redeclare variables anyway – niceman Mar 05 '17 at 07:04
  • @niceman I never said they should, just pointing out why the answer works and why. – Andrew Li Mar 05 '17 at 07:04
  • @AndrewLi Yes, noted at Answer that the variables are set globally; alternatively `({done, x, y, z} = someFunc(x, y, z));` – guest271314 Mar 05 '17 at 07:06
  • @guest271314 I would also tell the OP not to use implicit globals like `done = false`. – Andrew Li Mar 05 '17 at 07:06
  • @AndrewLi `done` appears to be explicit global variable from perspective here. – guest271314 Mar 05 '17 at 07:09
  • 1
    @guest271314 No, in the OPs code, they are doing `done = false` which is an implicit global. You should never declare a variable without var/let/const. – Andrew Li Mar 05 '17 at 07:10
  • @AndrewLi Can you provide further detail? How is `done = false` not explicitly global? – guest271314 Mar 05 '17 at 07:12
  • 1
    @guest271314 We might have a misunderstanding. By implicitly global, I mean it's declared without var/let/const and *implied* to be global. It would throw an error in strict mode. – Andrew Li Mar 05 '17 at 07:13
  • @guest271314 What error? I just said to include the fact that declaring a variable without var/let/const is bad practice. – Andrew Li Mar 05 '17 at 07:18
  • @AndrewLi Try to avoid using terms "good practice", "bad practice" here, though gather what you are conveying https://jsfiddle.net/k5howd7v/1/, https://jsfiddle.net/k5howd7v/2/. – guest271314 Mar 05 '17 at 07:19
  • @AndrewLi https://jsfiddle.net/k5howd7v/3/. Though `x` array will only contain `0` as 0 multiplied by positive number will be 0. – guest271314 Mar 05 '17 at 07:26
  • @AndrewLi Feel free to edit Answer to include proper description of what you have conveyed at comments, if you believe that Answer can be improved. – guest271314 Mar 05 '17 at 07:40
0

If you pass an object of data, it is possible to alter the values of the object without the need of return code.

var iterations = 0;

function someFunc(obj) {

    for (var i = 0; i < 4; i++) {
        obj.x[i] = obj.x[i] * 2;
        obj.y[i] = obj.y[i] * 2;
        obj.z[i] = obj.z[i] * 2;
    }

    iterations++;

    if (iterations >= 10)
        obj.done = true;
    else
        obj.done = false;

}

function main() {

    var objectOfData = {
        x: [0, 0, 0, 0],
        y: [1, 1, 1, 1],
        z: [2, 2, 2, 2],
        done: false,
    };

    while (!objectOfData.done) {

        someFunc(objectOfData);
        console.log(JSON.stringify(objectOfData));
        // Using stringify, as console.log() is async

        // Do some other stuff with x,y,z here,
        // like calling anotherFunc(x, y, z)

    }
}

Also, you only need to declare a vairable once var, let, etc

Jason
  • 779
  • 1
  • 9
  • 30