老生常谈:JS中的This
每个JS函数都有自己的运行环境,这个环境在函数内部用this来指代。this对象是在运行时根据函数的执行环境来绑定的,在全局环境中,this指向window对象;而当函数被当作一个对象的方法来调用时,this就是这个对象。
值得注意的一点是,函数的执行环境是它的直接调用对象。也就是说,即便是通过两层或多层对象调用了一个函数,它的执行环境仍然是离它最近的那个对象:
Animal.action.eat(); //eat函数的执行环境是action,而不是Animal
所以this对象是用来指代函数的运行环境的。
let user = {
name: 'paykan',
say: function(){
console.log(this.name)
}
}
user.say(); //paykan,此时的运行环境是user对象
let func = user.say;
func(); //undefined,此时的运行环境是window
在编码的过程中,我们很容易将函数的运行环境搞错,除非特别仔细,那么可以通过解答这个问题来消除这种担心:如何为函数指定运行环境?
设置函数的运行环境:call、apply、bind
还是上面的代码,如果我不太确定一个函数的运行环境将会是什么,那我可以在调用它时明确地指定(this是在执行时才确定的)。
/*方法一:call*/
document.body.onclick = function(){
functin fun(){ ... }
fun.call(this) //onclick函数执行环境肯定是body,所以此处的this是body
//写成fun.call(document.body)也一样
}
/*方法二:apply*/
document.body.onclick = function(){
functin fun(){ ... }
fun.apply(this)
}
/*方法三:bind*/
document.body.onclick = function(){
functin fun(){ ... }
fun.bind(this)() //bind返回了一个经过改装的函数
}
其实call、apply、bind只是在写法上不同而已:
- call(对象, 参数1, 参数2, ...)
- apply(对象, [参数1, 参数2, ...])
- bind(对象, 参数1, 参数2, ...),返回了一个经过改装的函数。
箭头函数中的this
在this的问题上,箭头函数让事情变得简单了一点——函数的this就是定义函数的那个执行环境。
比如在下面的代码中:
let user = {
id: "123456",
sayId: ()={
console.log(this.id)
}
}
user.sayId() //undefined
虽然this出现的位置是user对象,但this指向的绝不是user,而是它所在的那个箭头函数被定义时的执行环境:window——整个user对象是在window执行环境下定义的。
为了验证这一点,我们这样改写:
let user = {
id: "123456",
sayId: function(){
let fun = ()={ console.log(this.id) }
fun()
}
}
user.sayId() //123456
根据普通函数的特性,执行user.sayId时,该函数的执行环境就是user对象。在user这个执行环境里,我们定义了一个箭头函数。根据箭头函数的特性,它的执行环境在定义时就已经被绑定为user对象,所以该箭头函数内的this肯定指向了user对象。