美文网首页
JavaScript中的this

JavaScript中的this

作者: 饥人谷_御风 | 来源:发表于2017-12-15 21:20 被阅读0次

    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 的调用位置
    

    绑定规则

    默认绑定

    最常用的函数调用类型:独立函数调用。可以把这条规则看做是无法应用其他规则时的默认规则
    举例:

    function foo() {
        console.log(this.a)
    }
    
    var a = 2
    
    foo()   //2
    

    在本例中。函数调用时应用了this的默认绑定,因此this指向全局对象。因为在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能默认绑定。

    隐式绑定

    调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。
    举例:

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

    调用位置使用obj上下文来引用函数,隐式绑定规则会把函数调用中的this绑定在这个上下文对象中。
    但是要注意隐式丢失:
    被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而绑定在全局对象或者undefined中。举例:

    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
        foo: foo
    };
    var bar = obj.foo; // 函数别名!
    var a = "oops, global"; // a 是全局对象的属性
    bar(); // "oops, global"
    

    显式绑定

    使用函数的call()和apply()方法来直接指定this的绑定对象。
    当传入了一个基本类型值来当做this的绑定对象,这个值会被转换成对应的对象形式,这通常被称为“装箱”。

    硬绑定

    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
    };
    
    var bar = function() {
        foo.call(obj)
    }
    bar()   //2
    setTimeout(bar, 100)    //2
    //硬绑定的bar无法改变它的this
    bar.call(window)    //2
    

    这是一种显式的强制绑定,因此称为硬绑定
    典型应用场景:

    1. 创建一个包裹函数,负责接收参数并返回值
    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
    
    1. 创建一个可以重复使用的辅助函数
    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绑定

    在Javascript中,构造函数只是一些使用new操作符时被调用的函数,它们并不属于哪一类,也不会实例化一个类。实际上,它们甚至都不能说是一种特殊的函数类型,它们只是被new操作符调用的普通函数而已。
    使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

    1. 创建(或者说构造)一个全新的对象。
    2. 这个新对象会被执行[[prototype]]连接。
    3. 这个新对象会绑定到函数调用的this。
    4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
    function foo(a) {
        this.a = a;
    }
    var bar = new foo(2);
    console.log(bar.a); // 2
    

    使用new来调用foo()时,我们会构造一个新对象并把它绑定到foo()调用中的this上。new是最后一种可以影响函数调用时this绑定行为的方法,我们称为new绑定。

    判断this

    1. 函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。
    2. 函数是否通过call、apply(显式绑定)或者硬绑定调用?this绑定的是指定的对象。
    3. 函数是否在某个上下文对象中调用(隐式绑定)?this绑定的是那个上下文对象。
    4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象。

    绑定例外

    相关文章

      网友评论

          本文标题:JavaScript中的this

          本文链接:https://www.haomeiwen.com/subject/mtdlwxtx.html