javascript的this指向问题深度解析
参考来源[https://segmentfault.com/a/1190000008400124]
-
javascript函数中的this指向并不是函数定义的时候确定的,而是在调用的时候确定的。相当于,函数的调用方式决定了this指向。
-
js中普通函数的调用有三种方试:
-
直接调用
-
方法调用
-
new调用
-
除外,还有些比如通过bind()将函数绑定到对象之后再调用、通过call()、apply()进行调用等。
-
-
直接调用的this指向问题
-
就是直接通过函数名这种方式调用。这时候的函数内部的this指向全局对象,在浏览器中全局对象是window,在nodejs中全局对象是global。
-
需要注意的是,直接调用并不是指在全局作用域下调用,在任何作用域下,直接通过函数名()来对函数进行调用的方式,都是直接调用。
-
bind()对直接调用的影响
-
function.prototype.bind()的作用是将当前函数与指定的对象绑定,并返回一个新函数,这个新函数无论以什么样的方式调用,其this始终指向绑定的对象。
var obj = {}; function test() { console.log(this===obj); } var testObj = test.bind(obj); test(); //false testObj(); //true
-
call()和apply()对this的影响
-
function.prototype.apply()与function.prototype.call(),他们的第一个参数都是指定函数运行时其中的this指向。
-
不过使用aplly和call的时候,要注意,如果目录函数本身就是一个绑定了this对象的函数,那apply和call不会像预期的那样执行(所以慎用bind())。
const obj = {}; function test() { console.log(this === obj); } // 绑定到一个新对象,而不是 obj const testObj = test.bind({}); test.apply(obj); // true // 期望 this 是 obj,即输出 true // 但是因为 testObj 绑定了不是 obj 的对象,所以会输出 false testObj.apply(obj); // false
-
-
-
方法调用
- 方法调用是指通过对象来调用其方法函数,它是对象.方法函数()这样的调用形式。这种情况下,函数中的this指向调用该方法的对象。但是,同样需要注意bind()的影响。
const obj = { // 第一种方式,定义对象的时候定义其方法 test() { console.log(this === obj); } }; // 第二种方式,对象定义好之后为其附加一个方法(函数表达式) obj.test2 = function() { console.log(this === obj); }; // 第三种方式和第二种方式原理相同 // 是对象定义好之后为其附加一个方法(函数定义) function t() { console.log(this === obj); } obj.test3 = t; // 这也是为对象附加一个方法函数 // 但是这个函数绑定了一个不是 obj 的其它对象 obj.test4 = (function() { console.log(this === obj); }).bind({}); obj.test(); // true obj.test2(); // true obj.test3(); // true // 受 bind() 影响,test4 中的 this 指向不是 obj obj.test4(); // false
-
方法中this指向全局对象的情况
- 这里说的方法中而不是方法调用中。方法中的this指向全局对象,如果不是因为bind(),那就一定不是用的方法调用方式,如下:
const obj = { test() { console.log(this === obj); } }; const t = obj.test; t(); // false
-
t 就是 obj 的 test 方法,但是 t() 调用时,其中的 this 指向了全局。
-
提出上面的情况就是为了防止,在将一个对象方法作为回调传递给某个函数之后,却发现运行结果和想的完全不一样的情况发生(忽略了调用方式对this的影响),如下:
class Handlers { // 这里 $button 假设是一个指向某个按钮的 jQuery 对象 constructor(data, $button) { this.data = data; $button.on("click", this.onButtonClick); } onButtonClick(e) { console.log(this.data); } } const handlers = new Handlers("string data", $("#someButton")); // 对 #someButton 进行点击操作之后 // 输出 undefined // 但预期是输出 string data
- this.onButtonClick作为参数传入on()之后,事件触发时,是对函数的直接调用,而不是方法调用,所以其中的this会指向window全局对象
-
new调用
- 在es5中,用new调用一个构造函数,会创建一个新对象,而其中的this就指向的这个新对象。
var data = "Hi"; // 全局变量 function AClass(data) { this.data = data; } var a = new AClass("Hello World"); console.log(a.data); // Hello World console.log(data); // Hi var b = new AClass("Hello World"); console.log(a === b); // false