《你不知道的JavaScript(上卷)》笔记:this全面解析-绑定规则

调用位置

  • 调用位置就是函数在代码中被调用的位置,而不是声明的位置;
  • 最重要的是 分析调用栈;
  • 注意是如何从调用栈中分析出真正的调用位置的,它决定了this的绑定;我们关心的调用位置就在当前正在执行的函数的前一个调用中:

    function baz() {
        // 当前调用栈是:baz
        // 因此,当前调用位置是全局作用域
    
        console.log("baz");
        bar(); // bar的调用位置
    }
    
    function bar() {
        // 当前调用栈是 baz -> bar
        // 因此,当前调用位置在baz中
    
        console.log('bar');
        foo(); // foo 的调用位置
    }
    
    function foo() {
        // 当前调用栈是 baz -> bar -> foo
        // 因此,当前调用位置在bar中
    
        console.log("foo");
    }
    
    baz(); // baz的调用位置

绑定规则

  • 4种规则:默认绑定、隐式绑定、显式绑定、new绑定
  • 4种一则的优先级:new绑定、显示绑定、隐式绑定、默认绑定

默认绑定

  • 无法应用其他规则时的默认规则
  • 例子
function foo() {
    console.log(this.a);
}
var a = 2;
foo(); // 2

隐式绑定

  • 下面一段代码中,需要注意foo()的声明方式,无论是直接在obj中定义,还是先定义再添加为引用属性,这个函数严格来说都不属于obj对象。
  • 调用位置会使用obj上下文来引用函数
  • 当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
function foo() {
    console.log( this.a );
}
var obj = {
    a:2,
    foo: foo
}

obj.foo(); //2
  • 对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。
function foo() {
    console.log( this.a );
}

var obj2 = {
    a: 42,
    foo: foo
}
var obj1 = {
    a:2,
    obj2: obj2
}

obj1.obj2.foo(); // 42
  • 隐式丢失
function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
}
var bar = obj.foo;
var a = "opps";
bar(); // opps
function foo() {
    console.log( this.a );
}
function doFoo(Fn) {
    // fn其实引用的是foo
    fn(); // 调用位置
}
var obj = {
    a: 2,
    foo: foo
}

var a = "opps";
doFoo( obj.foo ); // "opps"

显示绑定

  • JavaScript提供的绝大多数函数已经自己创建的函数都可以使用call(…)和apply(…)方法。
  • 它们到第一个参数时一个对象,是给this准备的,接着在调用函数时将其绑定到this。
  • 硬绑定
function foo() {
    console.log(this.a);
}

var obj = {
    a : 2
}

var bar = function() {
    foo.call(obj);
}

bar(); //2
setTimeout(() => {
    bar(); //2
}, 100);

bar.call(window); //2
  • 硬绑定的典型应用场景就是创建一个包裹函数,负责接收参数并返回值
function foo(something) {
    console.log(this.a, something);
    return this.a + something;
}
var obj = {
    a:2
}

var bar = function(){
    return foo.apply(obj, arguments);
}

var b = bar(3); // 2 3
console.log(b); // 5
  • 创建一个可以重复使用的辅助函数
function foo(something) {
    console.log(this.a , something);
    return this.a + something; 
}
//简单的辅助绑定函数
function bind(fn, obj) {
    return function() {
        return fn.apply(obj, arguments);
    }
}

var obj = {
    a: 2
}

var bar = bind(foo, obj);
var b = bar(3); // 2 3
console.log(b); // 5 
  • ES5提供了内置的方法 Function.prototype.bind。

new绑定

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

function foo(a) {
    this.a = a;
}

var bar = new foo(2);
console.log( bar.a ); //2

猜你喜欢

转载自blog.csdn.net/wuweitiandian/article/details/79508281