0

The following segment:

var obj = {
    name:'Tom',
    sayHello:function() {
        console.log("hello," + this.name);
    }
}
var name = 'Kevin';

var method = obj.sayHello;
method();

will get the output:

hello,undefined

but, if change var name = 'Kevin'; to name = 'Kevin'; The output will be hello,Kevin. Why they are different?

4 Answers 4

3

There are two halves to the answer:

  1. When you use var method = obj.sayHello;, you are decoupling the function from obj. When you invoke the a method without giving it an explicit object, (ie, method() instead of obj.sayHello()), JavaScript sets this to the global object, window.

  2. When you define a variable using var name = 'Kevin', you're creating a local variable with function scope. When you define a variable using name = 'Kevin', you're creating a global variable, attached to the global object, window. This is identical to writing window.name = 'Kevin'.

These two things combine to mean that, inside sayHello, this is window and this.name is Kevin.

To solve this, you need to use bind, which returns a copy of your method with its context fixed to the object provided as an argument to bind:

var method = obj.sayHello;
new_method = method.bind(obj);
new_method(); // hello, Tom
Sign up to request clarification or add additional context in comments.

Comments

2
    sayHello:function() {
        console.log("hello," + this.name);
    }

this in this function refers to the global object. When you change var name = 'Kevin'; to name = 'Kevin';, name variable is set in the global object. Since, name is set in global and this is global, this.name refers to Kevin and it prints hello,Kevin.

Comments

1

The this keyword can be tricky to get.

If you call obj.sayHello, the this keyword will refer to obj. When you write method = obj.sayHello that the same thing that writing:

window.method = function() { console.log("hello," + this.name); }

The this keyword will now refer to window. That's why when you reference a variable having name for its name, you write window.name which can be found by your function.

Comments

1

How you call a function determines the value of this in the method. In your way of calling:

var method = obj.sayHello;
method();

You are losing the obj reference to this inside of your invocation of sayHello() so this is set to the global object or undefined, not set to obj. Thus, the errors you are getting.

When you do this:

var method = obj.sayHello;

All, it does it put a reference to the sayHello function in the method variable. Nowhere is anything to do with obj stored in method. So, when you then call method(), there is no object reference at all so instead of obj.sayHello() which causes this to be set to obj, you're just calling sayHello() all by itself which does not set the value of this to obj.


There are multiple ways to fix it.

1) Helper Function.

var method = function() {obj.sayHello()};
method();

2) Use .bind()

Here .bind() will create a helper function for you.

var method = obj.sayHello.bind(obj);
method();

3) Change sayHello() method

You can change the sayHello() method so it doesn't use the this pointer (which works fine if it is a singleton object, but not if there are multiple instances):

sayHello:function() {
    console.log("hello," + obj.name);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.