JavaScript的this关键字的小结¶
在Java等面向对象语言里,this的功能是比较清晰的,它一定是指向当前对象(正在被调用的方法所属的对象)。
而在JS里,情况会更复杂些。
JS this的几种不同指向¶
- 在对象的方法里,this指向该对象。
- 在函数里:
- 严格模式下,this的值为undefined。
- 非严格模式下,this指向全局对象。
- 在脚本里(不在方法或者函数)里,this指向全局对象。
call()、apply()、bind()可以让this指向任意对象。- ES6箭头函数里的this和上面的几种this有本质的不同,它实际上和箭头函数上下文里的this是同一个this。听起来有点费解,具体请看最后面的章节。
注意:
- 全局对象(global object),在浏览器环境下是指
window对象 - 在JS里,函数和方法是不同的概念!具体见下个章节。
方法vs函数¶
先看一个方法的例子:
const user = {
username: "jack",
hello : function() {
console.log('hello ' + this.username)
}
};
user.hello();
输出:
hello jack
当执行user.hello()方法时,方法内部的this指向的实际是user对象,因此输出的this.username等同于user.username。
接着上面的代码,我们再补充一个函数例子:
var hello = user.hello;
hello();
输出:
hello undefined
上面的代码里,我们将方法user.hello赋值给hello变量,然后再执行hello(),结果,输出变了,this.username不再是jack,而是undefined。
之所以出现这个怪相,是因为,hello变量是一个函数,而不是方法,只有对象名.方法名()的形式才是方法调用,其他情况是函数调用!根据我们前面对this的解释,在函数中,this指向全局对象window(暂不考虑strict模式),那么函数内部的this.username就等同于window.username,而window没有username属性,即,window.username的值是undefined。
call()、apply()、bind()的比较¶
三者都可以指定this的值。我们接下来通过代码示例来了解它们。
首先,准备好这两个对象,jack对象拥有一个hello方法,tom对象没有方法。我们将分别通过call()、apply()、bind()来让jack.hello()方法中的this指向tom对象。
const jack = {
username: "jack",
hello : function(times) {
for(let i = 0; i < times; i++) {
console.log('hello ' + this.username);
}
}
};
const tom = {username: "tom"};
借助call():
jack.hello.call(tom, 2);
借助apply():
jack.hello.apply(tom, [2]);
借助bind():
var hello = jack.hello.bind(tom);
hello(2);
上述三段代码的输出都是:
hello tom
hello tom
上述3个代码段,都实现了我们想要的效果,hello方法得到正常运行,而且输出的this.username实际确实是tom的username,而不是jack的username。
注意:
- call和apply的功能类似,都是修改函数的this并执行函数。区别在于,前者的函数参数是直接传入的,后者的函数参数是打包成一个数组传入的。
- bind不会立即执行函数,而是返回一个新函数。
ES6箭头函数的this¶
ES6箭头函数里的this和上面的几种this有本质的不同,它实际上和箭头函数上下文里的this是同一个this。
这个说法有点拗口,我们直接看代码:
const jack = {
username: "jack",
hello: () => console.log(this.username)
};
jack.hello();
这段代码的输出是undefined,而不是"jack"。看上去很不符合直觉,因为,假如hello不是箭头函数,而是普通function的时候,this应当会绑定到(指向)jack对象,那么jack.hello()输出的this.username就应该是"jack"。
实际上,箭头函数() => console.log(this.username)内部的所谓this实际上和箭头函数外部的this是同一个东西!箭头函数内部只是访问了一下上下文里的this。示例代码里,箭头函数的上下文就是定义jack变量、执行jack.hello();的这段代码,对于这段代码而言,this自然指向window。于是,箭头函数里访问this.username等同于访问window.username!
本文为kyleblog.cn原创,转载请注明出处:https://www.kyleblog.cn/posts/js_this