前言
什么是this
- 有一个误解是this,是指向自身。学习this的第一步是明白this并不指向自身,也不指向函数的词法作用域
- this是在运行时进行绑定的,并不是在编写时进行绑定的。
- this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式
this指向的分析
调用栈和调用位置
js中的函数是一个一个调用的,分析出函数的调用栈并找出调用位置,调用位置则是在调用栈当前位置的前一个函数中。
例:
function fun1(){
console.log('这是第一个函数')
//调用栈 fun1
//调用位置则是在fun1前一个,即为全局环境
func2()
}
function fun2(){
console.log('这是第二函数')
//调用栈 fun1 -> fun2
//调用位置则是在fun2前一个,即为fun1
fun3()
}
function fun3(){
//调用栈 fun1 -> fun2 -> fun3
//调用位置则是在fun3前一个,即为fun2
console.log('这是第三个函数')
}
fun1() //调用fun1
复制代码
绑定规则
根据函数的调用位置分析到底应用哪一条绑定规则,多条规则都可用时,规则的优先级。
-
默认绑定:独立函数调用(无法应用其他规则时的默认规则)。
独立函数的调用this指向全局,即使调用位置在另外一个函数中,指向的也是全局
例:function test(){ const a = 'aaa' test2() } function test2(){ console.log("this指向的测试",this.a) //this指向的测试,undefined(严格模式下this指向undefined,则this.a会抛出错误) } test() 复制代码
-
隐式绑定:调用位置是否有上下文。
如果被对象拥有或者包含,通过引用调用,this则指向该对象。
例:function foo(){ console.log(this.a) } const obj = { a: 2, fun:foo } obj.fun() //2 复制代码
注意:对象属性引用链只有在最后一层调用位置中起作用
例:function foo(){ console.log(this.a) } const obj1 = { a: 20, obj2:obj2 } const obj2 = { a: 10, fun:foo } obj1.obj2.fun() //10,指向的是最后一层调用链,obj2 复制代码
注意:隐式绑定this丢失,当通过引用赋值将对象函数赋给一个变量,再通过变量调用函数,则相当于是独立函数的调用,走默认规则,this则指向全局(严格模式下指向undefined)
例:function foo(){ console.log(this.a) } const obj = { a: 10, fun:foo } const test = obj.fun test() //undefined 复制代码
-
显示绑定 – call、bind、apply改变this的指向
call和bind的用法一样,区别是是否立即执行(call立即执行,bind不会立即执行)。function foo(){ console.log(this.a) } function foo1(){ console.log(this.a) } const obj = { a:1 } foo.call(obj) //1 foo1.bind(obj) foo1() //1 复制代码
注意:一旦硬绑定之后,this的指向就无法再发生改变
-
new绑定
可以通过new给函数创建一个指向函数内部的this
例:function foo(){ console.log(this.a) } function foo(){ console.log(this.a) } const obj = { a:1 } 复制代码
-
箭头函数:根据外层(函数或者全局)作用域来决定this。箭头函数this的指向不能改变
例:function foo(){ return () => { //继承自foo console.log(this.a) } } const obj1 = { a:1 } const obj2 = { a:2 } const fun = foo.call(obj1) fun.call(obj2) //1 复制代码
总结
如果要判断一个运行中函数的this绑定,就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断this的绑定对象。
- 由new调用?绑定到新创建的对象。
- 由call或者apply(或者bind)调用?绑定到指定的对象。
- 由上下文对象调用?绑定到那个上下文对象。
- 默认:在严格模式下绑定到undefined,否则绑定到全局对象。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END