详解js的this指向问题

以下内容来自《你不知道的js》读书笔记

this提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将API设计得更加简洁并且易于复用。

this与函数的调用位置有关。

一、 this的绑定规则

  • 默认绑定
  • 隐式绑定
  • 显示绑定
  • new绑定

1. 默认绑定:即独立函数调用,this会绑定到全局对象上(非严格模式)

function foo(){
    console.log(this.a); // 2
}
var a=2;
foo();
注意:
对于默认绑定来说,决定this绑定对象的并不是调用位置是否处于严格模式,而是**函数体是否处于严格模式**。如果函数体处于严格模式,this会被绑定到undefined,否则this会被绑定到全局对象。

2. 隐式绑定:调用位置是否有上下文对象,this会被绑定到这个上下文对象。

function foo(){
    console.log(this.a);
}
var obj={
    a: 2,
    foo: foo
}

obj.foo();// 2
注意:
1.对象属性引用链中只有上一层或者说最后一层在调用位置中起作用,即obj.obj2.foo(),那么foo中的this被绑定到了obj2上。
2.隐式丢失:被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把this绑定到全局对象或者undefined上,取决于是否是严格模式。
    (1)将函数赋值给其他变量
    (2)函数作为另外一个函数的参数传递进去(严格意义上也属于(1))

    function foo(){
        console.log(this.a);// 42,发生了隐式丢失
    }
    var obj={
        a: 2,
        foo: foo
    }
    var a = 42;
    var foo2=obj.foo;
    foo2();

3. 显示绑定:可以直接指定this的绑定对象

  • call、apply
function foo(){
    console.log(this.a);
}
var obj={
    a: 2
}
foo.call(obj);// 2
  • 以下两种方式可解决丢失绑定问题:

    • 硬绑定:bind(硬绑定后的this不能再次修改)
    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj={a: 2};
    var bar = foo.bind(obj);
    var b = bar(3);// 2, 3
    console.log(b);// 5
    • API调用的“上下文”:第三方库的许多函数,以及JavaScript语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文”

4. new绑定:在JavaScript中,构造函数只是一些使用new操作符时被调用的普通函数。

  • 创建(或者说构造)一个全新的对象。
  • 这个新对象会被执行[[Prototype]]连接。
  • 这个新对象会绑定到函数调用的this。
  • 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

**注意:this绑定的优先级:
new绑定 > 显示绑定 > 隐式绑定 > 默认绑定**

5. 箭头函数:不会使用以上四条标准的绑定规则,根据当前的词法作用域来决定this

二、 绑定例外

  • 被忽略的this:如果你把null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
  • 间接引用:你有可能(有意或者无意地)创建一个函数的“间接引用”,在这种情况下,调用这个函数会应用默认绑定规则。
function foo(){
    console.log(this.a);
}
var a = 2;
var o={a: 3, foo:foo};
var p={a:4};

o.foo();//3
(p.foo=o.foo)();// 2
// 赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。根据我们之前说过的,这里会应用默认绑定。
  • 软绑定:和硬绑定相同的效果,同时保留隐式绑定或者显式绑定修改this的能力。

如果this绑定到全局对象或者undefined,那就把指定的默认对象obj绑定到this,否则不会修改this

if(!Function.prototype.softBind){
    Function.prototype.softBind=function(obj){
        var fn=this;
        var curried=[].slice.call(arguments, 1);
        var bound=function(){
            return fn.apply(
            (!this || this === (window || global)) ? obj : this,
            curried.concat.apply(curried, arguments)
            )
        };
        bound.prototype=Object.create(fn.prototype);
        return bound;
    }
}

希望大家能持续关注哦,留一些个人信息方便大家找到我哦。知乎 github
附上个人公众号哦,希望大家前来骚扰(也会经常写一些随笔来记录生活,毕竟人生漫漫)
详解js的this指向问题_第1张图片

你可能感兴趣的:(javascript,前端,es6,this,this的用法)