JavaScript的回调函数内部this的指向问题以及四种绑定this指向的方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mr_28/article/details/78344321

1、常见回调函数内部的this指向问题
我们先看下面这段代码:

var o = {
    age : 12,
    say : function() {
        function callback() {
            return this.age;
        }
        func(callback);
    }
};

function func(callback) {
    var name = "Xiao Ming";
    console.log(name + " is " + callback() + " years old.");
}
o.say();

代码分析:这里创建了一个单例对象【o】和一个普通函数【func】,【o】中有一个方法【say】,在方法【say】里面调用了函数【func】,并传入了一个回调函数【callback】作为参数,【callback】中返回了对象【o】的属性【age】。当执行到函数【func】时,打印的结果如下:

console.log(name + " is " + callback() + " years old.");    //Xiao Ming is undefined years old.

我们可以看到【func】中执行的回调函数【callback】的返回结果是“undefined”而非“12”。
原因如下:函数内部的【this】指向于此函数的调用者(拥有者)。在上面这个例子中,虽然【callback】函数定义于对象【o】的【say】方法中,但实际上由于【callback】是在【func】函数中进行的普通调用,那么【func】中的【callback】的调用者我们便可以理解为是【window】对象,因此,【callback】中的【this】便指向了【window】,而在全局作用域中由于并不存在变量【age】,所以“this.age”(即“window.age”)便不存在,就返回了“undefined”。这里多说一点:既然变量【age】不存在,那么在使用一个未定义的变量时怎么没有报错(即“Uncaught ReferenceError: age is not defined”)呢?因为,这里是“return this.age”(在这里相当于“return window.age”)而非“return age”,即当使用一个对象的未定义的属性时不会报错,并返回“undefined”,而直接使用一个未定义的变量时便会报错

那么我们该如何让【callback】中的【this】指向对象【o】,从而获得【age】的值呢?

2、绑定this指向的四种方法
2.1、方法一:
将【callback】中的

return this.age;

换成

return o.age;

即将【this】换成具体的对象【o】,如此,我们可以保证最后的打印结果是正确的:

console.log(name + " is " + callback() + " years old.");    //Xiao Ming is 12 years old.

当然,这个方法有点偏题了。而且,这种方式有个问题——对象内部用对象名【o】而非【this】时,就加深了内部代码与对象名的耦合性了。

2.2、方法二:
将【func】中对【callback】的调用方式

callback()

换成

callback.call(o)

或者

callback.apply(o)

或者

callback.bind(o)()

即通过使用方法【call/apply/bind】将【callback】内部的【this】指向对象【o】,便也可以得到正确的打印结果(此略,同上)。

2.3、方法三:
需要使用ES6的方法(如果您还没有学过的话,也可以顺便了解下),即将【say】中的【callback】的定义方式

function callback() {
    return this.age;
}

换成

var callback = () => this.age;

即换用箭头函数进行定义,关于箭头函数内部的【this】的理解,我这里引用下阮老师的一句话:箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。如此,这里定义的【callback】函数内部的【this】即便是【say】方法的【this】,而【say】方法是在代码段的最后由【o】调用的,所以,【say】的【this】指向的便是【o】了,因而,【callback】里的this的指向也是【o】。(打印结果同上,此略)

2.4、方法四:
代码换成

var o = {
    age : 12,
    say : function() {
        function callback(that) {
            return that.age;
        }
        func(this, callback);
    }
};

function func(that, callback) {
    var name = "Xiao Ming";
    console.log(name + " is " + callback(that) + " years old.");
}
o.say();

即通过将正确的【this】传递到【callback】中来保证最后得到正确的结果,不过要稍微复杂点。(打印结果同上,此略)

阅读更多
换一批

没有更多推荐了,返回首页