RickBrunstedt
RickBrunstedt

Reputation: 2001

How to pass variable to function and set new value to it?

I find it very hard to explain or search for this problem, so I'm asking Stack Overflow.

I'm asking user for user-input in the terminal several times and want to make a function out of it. A function that takes a question and a variable, and the input should be added to the variable.

This is my code:

var name = 'hello',
    age = '11'

var readline = require('readline');
// var rl = readline.createInterface(process.stdin, process.stdout);
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
var getInput = function(inputVariable, question, cb) {
  rl.question(question, function(answer) {
    inputVariable = answer;
    rl.close();
    cb();
  });
}

var askForName = function() {
  console.log(1,age, name);
  getInput(name, "What's your name? ", askForAge);
}
var askForAge = function() {
  console.log(2,age, name);
  getInput(age, "How old are you? ", printIt);
}
var printIt = function() {
  console.log("Hello, " + name);
  console.log(".. and " + age + " old.");
}

askForName();

Thanks!

Upvotes: 4

Views: 2601

Answers (4)

jherax
jherax

Reputation: 5267

you can use an Object instead a primitive value, because objects are passed by reference, meaning the memory address of the original object will be affected.

In the following example, by leveraging that feature in objects, I also used the Function.prototype.call() method, to set the execution context of the function (that is useful in case the answers variable is not global.

//outer variable
var answers = {
  name: "hello",
  age: "11"
};

var readline = require('readline');
// var rl = readline.createInterface(process.stdin, process.stdout);
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

function getInput (propertyName, question, cb) {
  var answers = this; //gets the context associated to the current function
  rl.question(question, function(answer) {
    answers[propertyName] = answer;
    rl.close();
    cb();
  });
}

function askForName () {
  console.log(1, answers);
  //sets the execution context of getInput
  getInput.call(answers, "name", "What's your name? ", askForAge);
}

function askForAge () {
  console.log(2, answers);
  //sets the execution context of getInput
  getInput.call(answers, "age", "How old are you? ", printIt);
}

function printIt () {
  console.log("Hello, " + answers.name);
  console.log(".. and " + answers.age + " old.");
}

Upvotes: 1

Tobias
Tobias

Reputation: 7771

In node.js applications, this is usually solved using either a callback chain or promises.

Using callbacks, you could write your code like this:

var getInput = function(question, cb) {
  rl.question(question, function(answer) {
    // Don't set the variable, but return value to callback
    rl.close();
    cb(answer);
  });
}

// ask* take a callback which they call with the value
var askForName = function(cb) {
  getInput("What's your name? ", cb);
}
var askForAge = function(cb) {
  getInput("How old are you? ", cb);
}
// printIt takes the values as parameters
var printIt = function(name, age) {
  console.log("Hello, " + name);
  console.log(".. and " + age + " old.");
}

// Now ask for name and age and store them as local variables
// inside callbacks
askForName(function(name) {
  askForAge(function(age) {
    printIt(name, age);
  });
});

I added comments to explain the changes. Basically, the values are only being passed between callbacks, never exposed to another scope.

Upvotes: 3

Jonathon Hibbard
Jonathon Hibbard

Reputation: 1546

In javascript, only certain things are passed by reference - they are objects and arrays. all other primitive types (strings, integers, etc.) are not.

With that being said, there are a number of ways for you to get what you are after here.. especially since age and name are essentially globals (at least in the current scope of things)

One way is to just have the getInput() method return the value you want, and then assign that to your global var. Another would be to just write setter methods for each global you're wanting to change. There are others, but those are the 2 easiest..

anyways, the following would resolve your issue:

var name = 'hello',
    age = '11'

var readline = require('readline');
// var rl = readline.createInterface(process.stdin, process.stdout);
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
var getInput = function(inputVariable, question, cb) {
  rl.question(question, function(answer) {
    if( inputVariable === 'name' ) {
        name = answer;
    } else if( inputVariable === 'age' ){
        age = answer;
    }
    rl.close();
    cb();
  });
}

var askForName = function() {
  console.log(1,age, name);
  getInput('name', "What's your name? ", askForAge);
}
var askForAge = function() {
  console.log(2,age, name);
  getInput('age', "How old are you? ", printIt);
}
var printIt = function() {
  console.log("Hello, " + name);
  console.log(".. and " + age + " old.");
}

askForName();

now, there are more elegant ways of doing this. for instance, you could create a map, you could change the if statements to a switch, you could have getInput return a string via the callback, etc.

Upvotes: 1

TbWill4321
TbWill4321

Reputation: 8676

When you pass a variable to a function, changing the reference to it will not affect the original variable. You can modify the variable's properties. However, that shouldn't be used as the main method of passing around variables.

A common way of passing a response from an asynchronous process is to use a callback function. You've almost got it:

var getInput = function( question, cb ) {
  rl.question(question, function(answer) {
    rl.close();
    cb(answer);
  });
}

var askForName = function( cb ) {
  getInput("What's your name? ", cb);
}
var askForAge = function( cb ) {
  getInput("How old are you? ", cb);
}
var printIt = function( name, age ) {
  console.log("Hello, " + name);
  console.log(".. and " + age + " old.");
}

askForName(function(name) {
  askForAge(function(age) {
    printIt( name, age );
  });
});

Upvotes: 1

Related Questions