这是我参与「第四届青训营 」笔记创作活动的第6天
一、This永远指向最后调用它的那个对象
打印:
解释:
1、a.fn() 约等于 window.a.fn() ,但最后调用fn的是a对象,所以fn中的this指向a。就算a中没有this.age这个属性,也不会继续向上一个对象/作用域中查找,因为name的查找已经限定在this中了,即this.name是在‘this’上下文中寻找name
2、let f = a.fn只是赋值,没有调用。fn() 约等于 window.fn() ,因为this永远指向最后调用它的那个对象,所以fn中的this指向window
在ES5中 a() 约等于window.a() ,严格模式下,全局对象是undefined
二:如何改变this指向:
demo
var name = 'windowsName'
var a = {
name: 'cherry',
fun1(){
console.log(this.name)
},
fun2(){
setTimeout(function() {
console.log(this)
this.fun1()
},3000)
}
}
a.fun2()
打印:
解释: 因为定时器内的回调函数在三秒后才执行,定时器setTimeout的执行环境和a对象的执行环境分开了,导致this指向了默认的window,window下没有fun1,所以报错了
解决:
方法一:箭头函数
箭头函数无this,继承自上层作用域的this。(普通函数/window才算作用域,对象不算作用域)
更改的部分:
fun2(){
console.log(this)
setTimeout(() => {
console.log(this)
this.fun1()
},3000)
}
如图:第一行打印的是fun2的this,第二行是箭头函数内的this和调用this.fun1打印的this.name
解释: 箭头函数定义时的上层作用域是fun2函数,所以箭头函数内的this指向fun2的this,都指向a对象,所以this.name打印出a对象的name:‘cherry’
方法二:
在调用这个函数的对象使用_this = this(如果不使用ES6,这应该是最不会出错的方式了)
更改的部分:
fun2(){
let _this = this
console.log(this)
setTimeout(function() {
console.log(_this)
_this.fun1()
},3000)
}
解释: 在fun2中用_this 保存了this,然后在定时器的回调中使用_this,指向的就是fun2中的this。
换种说法就是调用了上级作用域中的变量,于是与该作用域发生了关联,该作用域的变量保持活跃,于是可以在定时器的回调触发时,a作用域销毁时,还能调用上级作用域的变量。
方法三:使用call、apply、bind
更改的部分:
fun2(){
setTimeout(function() {
console.log(this)
this.fun1()
}.call(a),3000)
//或apply(a)、bind(a)()
}
弊端: this指向确实改变了,但是定时器也失效了,回调立即发生。
Fn.apply( thisArg [,argsArray ] )
(下面的‘=’代表等于,不是赋值)
1、在ES5非严格模式下,thisArg = null/undefined 时,this自动指向window全局对象;
2、thisArg = 原始值(数字、字符串、布尔值)时,this指向该原始值的自动包装对象
例如:apply(123),this指向Number自动包装对象
3、ThisArg = 对象,则this指向该对象
4、传参 [ArgsArray],包含多个参数的数组
区别:call 接收的传参是参数列表、bind接收的也是参数列表,但因为bind是创建一个新的函数,所以需要额外调用函数bind()()