JS this指向问题

9 篇文章 0 订阅
3 篇文章 0 订阅

JS this指向问题

​ 在了解this指向之前,我们需要先知道:**函数在声明时,没有属于它自身的this,只有在函数调用时,this才有明确的指向。**因此,大多数情况下,我们只需要关注函数的调用位置,至于函数定义位置,有时候可能不那么重要。

一、this的默认绑定(优先级1)

①在script标签中,this 默认指向全局的 window

<script>
	console.log({} === {})          // false      指针地址不同
	console.log(this === window)    //  ture      this 默认指向 window,指针地址相同
</script>

②函数独立调用,this 默认指向 window

<script>
	function test() {
		console.log(this)
	}
	test()   // window    这里实际上可以理解为 window 在调用 test(),即 window.test()
</script>

二、隐式绑定(优先级2)

谁调用,this 指向谁

let age = 18;
let obj = {
    age = 28,
    test: function() {
        console.log(this)    // obj
        
        function func() {
            console.log(this)    // window
        }
        func()
    }
}
obj.test()
// 毫无疑问,obj.test()执行时,test函数中的this肯定是指向obj
// 而在obj.test()执行过程中,func函数被定义,这时func中的this,并无实际意义,只有在func()在被调用时,this才有了实际的意义,这时,并不是obj在调用它(并不是obj.func()),而是func()被独立调用,因此指向window
// 上例改造 1
let age = 18;
let obj = {
    age = 28,
    test: function() {
        // 这里我们将func()返回出去,形成一个闭包
        // 闭包:可以理解为,定义在函数内部的函数
        return function func() {
            console.log(this)  // window
        }
    }
}
obj.test()()      // 通过这种方式来调用,实际上仍然输出 window,因为obj.test()实际上就是 func
// 再次改造 2
let age = 18;
// 这次我们将函数定义在对象外部
function test() {
    console.log(this)
}
let obj = {
    age = 28,
    test: test
}
obj.test()   // 这里会输出什么呢?   obj
// 由于obj中的test指向外部test()函数,因此我们可以直接把外部test()放到obj的test属性中,因此此处会输出 obj

let a = obj.test    // 这里只存在赋值,并没有调用,obj.test ≠ obj.test()
a()    // 这里的this又会输出什么呢?  window
// 实际上,由于a指向obj.test,而obj.test又指向外部的test函数,所以a实际上指向的还是外部的test函数,因此 a() 相当于 test(),this指向 window
// 进阶改造 3
let age = 18;
function test() {
    console.log(this)
}
// 定义一个函数,参数也为函数
function func(fn) {
    fn();   // 独立调用
    //  这里如果改写为 fn.call(obj) ,fn中的this就可以指向obj了
}
let obj = {
    a: 2,
    test: test
}

func(obj.test)    // 这里会输出什么呢?   window
// 由于obj.test指向外部test()函数,所以相当于将外部test()函数传给了func函数,而在func()函数中,test()被独立调用,因此指向window

三、显式绑定(call、apply、bind)(优先级3)

let a = 18
function test(a, b, c) {
    console.log(a, b, c)
    console.log(this)
}
let obj = {
    a: 28,
    test: test
}
let a = obj.test

// 简单看一下以下几种情况(this均指向obj)
obj.test(1, 2, 3)
a.call(obj, 1, 2, 3)
a.apply(obj, [1, 2, 3])
a.bind(obj)(1, 2, 3)

四、new 绑定(优先级4)

new过之后,this指向当前对象实例

function Person() {
	this.a = 1;
	this.test = function() {
		console.log(this)
	}
}
let p = new Person()
p.b = 2
p.test()  // {a: 1, test: f, b: 2}

五、优先级问题

new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

function test(b) {
    this.a = b
}
let obj = {}
let func = test.bind(obj1)
func(2)

console.log(obj.2)   // 由于bind将this指向obj1,所以此处输出 2

let o = new func(3)
console.log(obj.a)   // 由于new将this指向 o,所以此处仍然输出 2

console.log(o.a)   /// 3

六、箭头函数中的this

上面我们已经看过了非常多普通函数的this指向问题,那么箭头函数的this有哪些不一样呢?

箭头函数没有属于它自身的 this,它的this来自于外层作用域中的 this,会沿着作用域链一直往外层寻找 this。

let a = 0
function test() {
    console.log(this)
    
    function fn() {
        console.log(this)   // 上面我们已经知道,这里会输出 window
    }
    fn1()
    
    let fn2 = () => {
        console.log(this)   // 如果我们使用箭头函数,这里将输出 obj对象
    }
    fn2()
}
let obj = {
    a: 1,
    test: test
}
obj.test()
// 上例改造:验证箭头函数的默认绑定
let a = 0
function test() {
    console.log(this)
    
    let fn2 = () => {
        console.log(this)
    }
    return fn2()   // 这里我们将 fn2 返回出去
}
let obj = {
    a: 1,
    test: test
}
obj.test()()   // 这里是函数的独立调用,如果是普通函数,这里将输出 window,但 fn2 是箭头函数,这里将输出 obj对象

let o = test().call(obj)  // 这里是函数的显式调用,如果是普通函数,这里this 将指向obj,但 test() 返回的是一个箭头函数 fn2(),这里将输出 window

​ 由上例我们可以看出,箭头函数不会受到默认绑定规则(独立调用无效)和显式绑定的影响,它始终会沿着作用域链寻找可用 this。

// 再次改造:验证箭头函数的隐式绑定
let a = 0
let obj = {
    a: 1,
    test: () => {
        console.log(this)
    }
}
obj.test()   // 这里是函数的隐式调用,如果是普通函数,这里将输出 obj对象,但 obj.test 是箭头函数,这里将往外层寻找可用 this,即 window

​ 由上例我们可以看出,箭头函数不会受到隐式绑定规则的影响,它始终会沿着作用域链寻找可用 this。

// 再次改造:验证箭头函数的 new 绑定
let test() = () => {
    console.log(this)
}

new test()  // 报错: test is not a constructor

​ 由上例我们可以看出,箭头函数不是构造函数,无法使用 new 关键字。

综上所述:

①普通函数中的四种 this 绑定规则对箭头函数均无效。

②箭头函数中的 this 始终来自于作用域链中的可用 this。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值