zoukankan      html  css  js  c++  java
  • 如果判定 this 又混乱了,就从头再读一遍……

    this call apply bind

    this

    调用点

    this 是完全根据调用点(函数是如何被调用的)而绑定的。

    function baz() {
        // 调用栈是: `baz`
        // 我们的调用点是 global scope(全局作用域)
    
        console.log( "baz" );
        bar(); // <-- `bar` 的调用点
    }
    
    function bar() {
        // 调用栈是: `baz` -> `bar`
        // 我们的调用点位于 `baz`
    
        console.log( "bar" );
        foo(); // <-- `foo` 的 call-site
    }
    
    function foo() {
        // 调用栈是: `baz` -> `bar` -> `foo`
        // 我们的调用点位于 `bar`
    
        console.log( "foo" );
    }
    
    baz(); // <-- `baz` 的调用点
    

    可以通过 debugger 来获取调用链

    this的四种规则

    1. 默认绑定

    对此方法调用的 this 实施了 默认绑定,所以使 this 指向了全局对象。

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

    严格模式下,

    function foo() {
        "use strict";
    
        console.log( this.a );
    }
    
    var a = 2;
    
    foo(); // TypeError: `this` is `undefined`
    

    2. 隐含绑定

    调用点是否有一个环境对象?

    调用点 使用 obj 环境来 引用 函数,所以你 可以说 obj 对象在函数被调用的时间点上“拥有”或“包含”这个 函数引用

    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
    

    3. 隐含丢失

    当一个 隐含绑定 丢失了它的绑定,这通常意味着它会退回到 默认绑定, 根据 strict mode 的状态,其结果不是全局对象就是 undefined

    bar 似乎是 obj.foo 的引用,但实际上它只是另一个 foo 本身的引用而已。

    另外,起作用的调用点是 bar(),因此this指向全局对象。

    function foo() {
        console.log( this.a );
    }
    
    var obj = {
        a: 2,
        foo: foo
    };
    
    var bar = obj.foo; // 函数引用!
    
    var a = "oops, global"; // `a` 也是一个全局对象的属性
    
    bar(); // "oops, global"
    
    function foo() {
        console.log( this.a );
    }
    
    function doFoo(fn) {
        // `fn` 只不过 `foo` 的另一个引用
    
        fn(); // <-- 调用点!
    }
    
    var obj = {
        a: 2,
        foo: foo
    };
    
    var a = "oops, global"; // `a` 也是一个全局对象的属性
    
    doFoo( obj.foo ); // "oops, global"
    

    3. 明确绑定

    函数拥有 call(..)apply(..) 方法。

    它们接收的第一个参数都是一个用于 this 的对象,之后使用这个指定的 this 来调用函数。

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

    如果你传递一个简单基本类型值(stringboolean,或 number 类型)作为 this 绑定,那么这个基本类型值会被包装在它的对象类型中(分别是 new String(..)new Boolean(..),或 new Number(..))。这通常称为“封箱(boxing)”。

    4. 硬绑定

    function foo() {
        console.log( this.a );
    }
    
    var obj = {
        a: 2
    };
    
    var bar = function() {
        foo.call( obj );
    };
    
    bar(); // 2
    setTimeout( bar, 100 ); // 2
    
    // `bar` 将 `foo` 的 `this` 硬绑定到 `obj`
    // 所以它不可以被覆盖
    bar.call( window ); // 2
    

    实现bind:

    function foo(something) {
        console.log( this.a, something );
        return this.a + something;
    }
    
    // 简单的 `bind` 帮助函数
    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
    

    各种绑定的优先级

    明确绑定 的优先级高于 隐含绑定:

    function foo() {
        console.log( this.a );
    }
    
    var obj1 = {
        a: 2,
        foo: foo
    };
    
    var obj2 = {
        a: 3,
        foo: foo
    };
    
    obj1.foo(); // 2
    obj2.foo(); // 3
    
    obj1.foo.call( obj2 ); // 3
    obj2.foo.call( obj1 ); // 2
    

    new绑定 优先级高于 隐含绑定

    function foo(something) {
        this.a = something;
    }
    
    var obj1 = {
        foo: foo
    };
    
    var obj2 = {};
    
    obj1.foo( 2 );
    console.log( obj1.a ); // 2
    
    obj1.foo.call( obj2, 3 );
    console.log( obj2.a ); // 3
    
    var bar = new obj1.foo( 4 );
    console.log( obj1.a ); // 2
    console.log( bar.a ); // 4
    

    按照优先级顺序 判定this

    1. 函数是通过 new 被调用的吗(new 绑定)?如果是,this 就是新构建的对象。

      var bar = new foo()
      
    2. 函数是通过 callapply 被调用(明确绑定),甚至是隐藏在 bind 硬绑定 之中吗?如果是,this 就是那个被明确指定的对象。

      var bar = foo.call( obj2 )
      
    3. 函数是通过环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,this 就是那个环境对象。

      var bar = obj1.foo()
      
    4. 否则,使用默认的 this默认绑定)。如果在 strict mode 下,就是 undefined,否则是 global 对象。

      var bar = foo()
      
      

    例外

    1. 传递 nullundefined 作为 callapplybindthis 绑定参数,那么这些值会被忽略掉,取而代之的是 默认绑定 规则将适用于这个调用。

      利用

  • 相关阅读:
    记第一次为开源代码报漏洞
    入职第三周——总结前两周学习内容
    入职一星期之感想
    毕业季之礼
    基于mint-ui的移动应用开发案例二(项目搭建)
    基于mint-ui的移动应用开发案例一(简介)
    工作笔记一——杂项
    微信小程序实战小小应用——豆瓣电影
    React学习之坑(二)- 基础入门
    React学习笔记(一)- 环境搭建
  • 原文地址:https://www.cnblogs.com/peekapoooo/p/14408947.html
Copyright © 2011-2022 走看看