6

I tried to console variable fullName after function run ,but it doesn't changed value ,just console default value Not Set,why was that?

function Test() {
    this.clientData = {
        fullName : "Not Set",
        setUserName: function (firstName, lastName) {
            this.fullName = firstName + " " + lastName;
        },
        getUserInput2: function (firstName, lastName, callback) {
            callback(firstName, lastName);
        }
    };

    this.getUserInput1 = function (firstName, lastName, callback) {
        callback(firstName, lastName);
    };
}

var test = new Test();

test.getUserInput1("A1", "B1", test.clientData.setUserName);

console.log("test.clientData.fullName : " + test.clientData.fullName);//Not Set
//expected => A1 B1

test.clientData.getUserInput2("A2", "B2", test.clientData.setUserName);
console.log("test.clientData.fullName : " + test.clientData.fullName);//Not Set
//expected => A2 B2
fredmaggiowski
  • 2,103
  • 2
  • 23
  • 42
David Jaw Hpan
  • 4,423
  • 1
  • 22
  • 49
  • 2
    Possibly a duplicate of [*`this` in callback functions*](http://stackoverflow.com/questions/14561723/this-in-callback-functions). Also you might like to read [*How does the “this” keyword work?*](http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work/3127440#3127440) and [*MDN: this*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this). – RobG Feb 19 '16 at 04:41

3 Answers3

3

It is because when the callbacks are called, the context(this) value of the callback is not the clientData object.

You can set the callback manualy using Function.bind()

function Test() {
  this.clientData = {
    fullName: "Not Set",
    setUserName: function(firstName, lastName) {
      this.fullName = firstName + " " + lastName;
    },
    getUserInput2: function(firstName, lastName, callback) {
      callback(firstName, lastName);
    }
  };
  this.getUserInput1 = function(firstName, lastName, callback) {
    callback(firstName, lastName);
  };
}

var test = new Test();
var userInput = new test.getUserInput1("A1", "B1", test.clientData.setUserName.bind(test.clientData));
snippet.log("test.clientData.fullName : " + test.clientData.fullName); //Not Set
//expected => A1 B1
test.clientData.getUserInput2("A2", "B2", test.clientData.setUserName.bind(test.clientData));
snippet.log("test.clientData.fullName : " + test.clientData.fullName); //Not Set
//expected => A2 B2
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Arun P Johny
  • 365,836
  • 60
  • 503
  • 504
  • Explain a bit about `.bind()`..+1 – Rayon Feb 19 '16 at 04:31
  • A function's *this* is but one parameter of its execution context, it's not **the** context. The OP's issue is that the callback's *this* isn't set to the right value, so that is what must be fixed (through bind, a closure or changing the call). – RobG Feb 19 '16 at 04:37
3

This is working. you can do this without using bind() function. you just need to store Test object in variable.

function Test() {
 var t = this
 this.clientData = {
          fullName : "Not Set",
          setUserName: function (firstName, lastName) {
          t.clientData.fullName = firstName + " " + lastName;
          },
          getUserInput2: function (firstName, lastName, callback) {
              callback(firstName, lastName);
          }
       };
 this.getUserInput1 = function (firstName, lastName, callback) {
     callback(firstName, lastName);
       };
 }

var test = new Test();
test.getUserInput1("A1", "B1", test.clientData.setUserName);
console.log("test.clientData.fullName : " + test.clientData.fullName);//Not Set
//expected => A1 B1
test.clientData.getUserInput2("A2", "B2", test.clientData.setUserName);
console.log("test.clientData.fullName : " + test.clientData.fullName);//Not Set
   
Hiren patel
  • 941
  • 5
  • 22
3

To understand clearly about the this statement, you must understand that it represents the current "scope" inside the function.

When you declare :

function Test() {
    this.clientData = {
    ....
    };
}

this represents the current scope of the Test function. That's why, when you will do var test = new Test();, you will be able to use test.clientData and then get access to data you set in the initialization of your object.

Now, inside your clientData property of your test object, you have a setUserName (I recommend you to name it setFullName) which is again a function (JavaScript is function scoped). So if we look at your code :

function Test() {
    this.clientData = {
        fullName: "Not Set",
        setFullName: function(firstName, lastName) {
            /*
             * `this` represents the scope of the `setFullName` function,
             *  and not the scope of the `Test` function
             */
            this.fullName = firstName + " " + lastName; 
        }
    };
}

So the trick is to store this in a variable in the top level, because JavaScript is function scoped, the variable will be available for every function inside the scope. So now we can do that :

function Test() {
    var self = this;
    self.clientData = {
        fullName: "Not Set",
        setFullName: function(firstName, lastName) {
            self.clientData.fullName = firstName + " " + lastName; 
        }
    };
}

I recommend you, to split your data and your method in a different way. Now you put everything in a clientData object that add some complexity to your app. You can separate the stored values (name, age, any storage information) and the methods that will interact with the data.

I suggest something like that :

function Person() {
    var self = this;
    self.fullName = "Not Set"
    self.setFullName = function(firstName, lastName) {
        self.fullName = firstName + " " + lastName; 
    };
}
var john = new Person();
john.setFullName("John", "Doe");
console.log("john.fullName : " + john.fullName); // Display : John Doe
var bruce = new Person()
bruce.setFullName("Bruce", "Wayne");
console.log("bruce.fullName : " + bruce.fullName); // Display : Bruce Wayne

This way you have a much easier code to read and a much easier code to execute. After, it is up to you to organize and design your object logic the way you want to.

Hope it helps.

Ganbin
  • 1,523
  • 1
  • 10
  • 19