js中的this指向问题

128 阅读2分钟

影响this绑定的四种情况

1、默认情况的绑定

function testC(){
        debugger;
        // 查看调用栈
        let c = 10
        console.log(this.testA)
    }
testC()

image.png

2、当函数被一个对象拥有或者包含的时候,this默认指向这个对象(隐性绑定)

//如果调用位置被对象拥有或者是被对象包围,需要考虑上下文对象
    function testD(){
        debugger
        console.log(this.a)
    }
    let obj = {
        a:12,
        test:function(){debugger; console.log(this.a)},
        testTwo:testD
    }
    //注意这里的要求是完全的拥有或者是包含,但是以下情况也是可以的
    // obj.test()
    obj.testTwo()

image.png 注意:这里需要注意一个隐性绑定丢失的问题

function foo(a){
        debugger;
        this.a = a
    }
    let objA = {
        a:1,
        foo:foo
    }
    objA.foo(3)

image.png

这里通过objA调用foo是没有问题的,但是当把objA.foo当作参数传递的时候会出现this绑定丢失的情况

function foo(a){
        debugger;
        this.a = a
    }
    let objA = {
        a:1,
        foo:foo
    }
    // objA.foo(3)
    let fooTwo = objA.foo
    fooTwo(5)

image.png

回掉函数中也是如此

 function foo(a){
        debugger;
        this.a = a
    }
    let objA = {
        a:1,
        foo:foo
    }
    setTimeout(objA.foo,5000)

image.png

3、显式绑定

通过apply和call显式的将this绑定到一个对象上

let obj = {
        a:'a',
        b:'b',
        c:'c'
    }
    function testA(){
        debugger;
        console.log(this.a)
        console.log(this.b)
        console.log(this.c)
    }
    testA.call(obj)

image.png

通过硬绑定绑定解决this绑定丢失的问题

function foo(a){
        // debugger;
        this.a = a
    }
    let objA = {
        a:1,
        foo:foo
    }
    function testBind(func,obj){
        return function(){
            return obj.call(func)
        }
    }
    let fooTwo = testBind(objA,foo)
    setTimeout(fooTwo,5000)

image.png

我个人的理解是当函数被当作值进行传递的时候this的绑定关系会丢失,硬绑定通过闭包函数重新的将this关系进行绑定

可以使用js的内置方法bind方法来实现硬绑定

function foo(a){
        this.a = a
        debugger;
    }
    let objA = {
        a:1,
        foo:foo
    }
    let fooTwo = foo.bind(objA,3)
    setTimeout(fooTwo,5000)

image.png

4、new 绑定 JavaScript中的new与其他面向对象中的new的方式有一些区别,其他面向对象中的new函数一般是类中的构造函数方法,而JavaScript中的new函数的调用则不同,它包括了以下的四步:

  • 1、创建一个空的对象
  • 2、创建原型链
  • 3、将this绑定到这个空对象
  • 4、如果没有返回则返回这个空的对象

5、特殊情况:箭头函数 JavaScript中的箭头函数并不是通过函数声明定义的,它的this是基于外层的作用域,及类似let that = this,这样的用法:

function foo(){
    return (a)=> {
        console.log(this.a)
    }
}
let objB = {
    a:8
}
var a = 2
let fooTwo = foo.call(objB)
fooTwo()

这里如果是普通函数的话应该是应用默认规则一,但是箭头函数的行为却不一样,它会根据外层的词法作用域去寻找,这里外层的foo绑定了objB:

image.png

箭头函数的this被绑定之后就不会在发生变化,类似词法作用域

function foo(){
        return (a)=> {
            console.log(this.a)
        }
    }
    let objB = {
        a:8
    }
    
    let fooTwo = foo.call(objB)
    let objC = {
        a:10
    }
    fooTwo.call(objC)

image.png

在回掉函数中也是如此

function foo(){
        return (a)=> {
            console.log(this.a)
        }
    }
    let objB = {
        a:8
    }
    
    let fooTwo = foo.call(objB)
    let objC = {
        a:10
    }
    setTimeout(fooTwo,5000)

image.png