• JavaScript中的 this


    面向对象语言中 this 表示当前对象的一个引用。但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

    • 单独使用(包括严格模式下),this 表示全局对象
    • 在函数中,this 表示全局对象
    • 在函数中,在严格模式下,this 是未定义的(undefined)
    • 在对象方法中,this 表示该方法所属的直接对象
    • 在事件中,this 表示接收事件的元素
    • 类似 call()、apply()、bind() 方法可以将 this 引用到任何对象

    this 的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定 this 到底指向谁,实际上 this 最终指向的是那个调用它的对象。

    单独使用 this

    单独使用 this,则它指向全局(Global)对象。在浏览器中,Window 就是该全局对象。

    var x = this;
    x // [object Window] 
    

    严格模式下,如果单独使用,this 也是指向全局(Global)对象。

    "use strict";
    var x = this;
    x // [object Window]
    

    函数中使用 this

    在函数中,this 指向调用函数的对象

    var color = 'Global color'; 
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // [Object Windwo]
      console.log(this.color); // 'Global color'
    }
    myFunction(); // 实质是全局对象window在调用函数 ==> window.myFunction();
    

    在严格模式下,this 是 undefined

    "use strict"
    var color = 'Global color'; 
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // undefined
      console.log(this.color); // TypeError: Cannot read property 'color' of undefined
    }
    myFunction(); 
    

    对象方法中使用 this

    在对象方法中,this 表示该方法所属的直接对象

    var color = 'Global color'; 
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // [Object myObj]
      console.log(this.color); // 'Object color'
    }
    var myObj = {
      color: 'Object color', 
    
      foo: myFunction
    };
    
    myObj.foo();
    

    有嵌套对象的场景(下列代码中 myFunction 方法所属的直接对象为 subObj ):

    var color = 'Global color'; 
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // [Object subObj]
      console.log(this.color); // 'SubObject color'
    }
    var subObj = {
      color: 'SubObject color',
      foo: myFunction
    };
    var myObj = {
      color: 'Object color', 
    
      subObj: subObj
    };
    
    myObj.subObj.foo();
    

    对象普通属性中使用 this

    对象属性由 普通属性 + 方法 构成,当对普通属性使用 this. 赋值时,this 始终指向全局对象(?? 没有完全理解)

    // 示例一(观察 myFunction 中 this.dangerColor 的输出)
    var color = 'Global color'; 
    var dangerColor = 'Global Danger color';
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // [Object myObj]
      console.log(this.color); // 'Object color'
      console.log(this.dangerColor); // 'Global Danger color'
    }
    var myObj = {
      color: 'Object color', 
      dangerColor: this.dangerColor, // 此处 this 指向全局对象 Window
      foo: myFunction
    };
    
    myObj.foo();
    
    // 示例二,有嵌套对象的场景,父对象、子对象单独定义(观察 myFunction 中 this.dangerColor 的输出)
    var color = 'Global color'; 
    var dangerColor = 'Global Danger color';
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // [SubObject myObj]
      console.log(this.color); // 'SubObject color'
      console.log(this.dangerColor); // 'Global Danger color' (?? 这个输出有点不太理解)
    }
    var subObj = {
      color: 'SubObject color',
      dangerColor: this.dangerColor, // 此处 this 就确定了? 指向全局对象 Window? (?? 不太理解)
      foo: myFunction
    };
    var myObj = {
      color: 'Object color', 
      dangerColor: 'Object Danger color',
    
      subObj: subObj
    };
    
    myObj.subObj.foo();
    
    // 示例三,有嵌套对象的场景,子对象直接在父对象中定义(观察 myFunction 中 this.dangerColor 的输出)
    var color = 'Global color'; 
    var dangerColor = 'Global Danger color';
    
    function myFunction() {
      var color = 'Function color';
    
      console.log(color); // 'Function color'  
      console.log(this); // [SubObject myObj]
      console.log(this.color); // 'SubObject color'
      console.log(this.dangerColor); // 'Global Danger color' (?? 这个输出有点不太理解)
    }
    
    var myObj = {
      color: 'Object color', 
      dangerColor: 'Object Danger color',
      // 子对象直接在父对象中定义
      subObj: {
        color: 'SubObject color',
        dangerColor: this.dangerColor, // 此处 this 就确定了? 指向全局对象 Window? (?? 不太理解)
        foo: myFunction
      }
    };
    
    myObj.subObj.foo();
    

    说明:当对 对象普通属性使用 this. 赋值时,感觉 this 始终指向全局对象,目前还不太理解??

    事件中的 this

    在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素

    <button onclick="this.style.display='none'">点我后我就消失了</button>
    

    this 的四种绑定规则

    this 的四种绑定规则分别是:默认绑定、隐式绑定、显示绑定、new 绑定

    默认绑定

    独立函数调用

    var color = 'Global color'; 
    
    function myFunction() {
      console.log(this.color); // 'Global color' (严格模式下有 undefined 的问题)
    }
    myFunction();
    

    隐式绑定

    函数的调用是在某个对象上触发的,调用位置上存在上下文对象(上文中的“对象方法中使用 this ”)

    var color = 'Global color'; 
    function myFunction() {
      console.log(this.color); // 'Object color'
    }
    var myObj = {
      color: 'Object color', 
      foo: myFunction
    };
    myObj.foo();
    
    隐式丢失(函数别名)
    var color = 'Global color'; 
    function myFunction() {
      console.log(this.color); // 'Global color'
    }
    var myObj = {
      color: 'Object color', 
      foo: myFunction
    };
    var bar = myObj.foo; // 不直接执行
    bar();
    

    说明:myObj.foo 是引用属性,赋值给 bar 的实际上就是foo函数(即:bar 指向 foo 本身)。那么,实际的调用关系是:通过 bar 找到 foo 函数,进行调用。整个调用过程并没有myObj 的参与,所以是默认绑定,输出结果为全局变量 color 的值 'Global color'。

    隐式丢失(回调函数)
    var color = 'Global color'; 
    function myFunction() {
      console.log(this.color); // 'Global color'
    }
    var myObj = {
      color: 'Object color', 
      foo: myFunction
    };
    
    setTimeout(myObj.foo, 1000);
    

    说明:同样的道理,虽然参传是 myObj.foo,因为是引用类型,所以传参实际上传的就是 foo 对象(函数)本身的引用。对于 setTimeout 的调用,还是 setTimeout -> 获取参数中 foo的引用参数 -> 执行 foo 函数,中间没有 myObj 的参与,这里依旧进行的是默认绑定。

    显示绑定

    相对隐式绑定,this 值在调用过程中会动态变化,如果我们就想绑定指定的对象,这时就用到了显示绑定。
    具体使用上,可以通过call(…)、apply(…) 或 bind(…)来实现。(三个方法的区别

    var person = {
      name: 'xx',
      age: 'xx',
      foo: function() {
        console.log(this.name + ', ' + this.age);
      }
    }
    var xiaoming = {
      name: '小明',
      age: 21
    }
    var zhangsan = {
      name: '张三',
      age: 31
    }
    var lisi = {
      name: '李四',
      age: 27
    }
    var bar = person.foo;
    bar.call(xiaoming); // 小明, 21
    bar.apply(zhangsan); // 张三, 31
    bar.bind(lisi)(); // 李四, 27
    

    硬绑定

    var person = {
      name: 'xx',
      age: 'xx',
      foo: function() {
        console.log(this.name + ', ' + this.age);
      }
    }
    var xiaoming = {
      name: '小明',
      age: 21
    }
    var zhangsan = {
      name: '张三',
      age: 31
    }
    var bar = function() {
      person.foo.call(xiaoming); 
    };
    
    setTimeout(bar, 1000); // 小明, 21
    
    bar.call(zhangsan); // 小明, 21 (!!!,这里需要注意)
    

    说明:虽然最后一行代码, bar 被显示绑定到 zhangsan 上,对于 bar,function(){…} 中的 this 确实被绑定到了 zhangsan 上,但 person.foo 因为通过 person.foo.call( xiaoming) 已经显示绑定了 xiaoming,所以在 foo 函数内,this 指向的是 xiaoming,不会因为 bar 函数内指向 zhangsan 而改变自身,所以打印的是 "小明, 21"。

    在显示绑定中,绑定 null 或 undefined,实际上会进行默认绑定,导致函数中可能会使用到全局变量,与预期不符。对于要忽略 this 的情况,可以传入一个空对象,该对象通过Object.create(null) 创建。

    var name = 'Window';
    var age = '100';
    var person = {
      name: 'xx',
      age: 'xx',
      foo: function() {
        console.log(this.name + ', ' + this.age);
      }
    }
    var xiaoming = {
      name: '小明',
      age: 21
    }
    var emptyObj = Object.create(null);
    var emptyObj2 = Object.create({});
    
    person.foo.call(null); // Window, 100
    person.foo.call(undefined); // Window, 100
    person.foo.call(xiaoming); // 小明, 21
    person.foo.call(emptyObj); // undefined, undefined
    person.foo.call(emptyObj2); // undefined, undefined
    

    new 绑定

    作为构造函数调用,this 指代 new 实例化的对象

    function Person(name) {
      this.name = name;  
    }
    var xiaoming = new Person('小明');
    console.log(xiaoming.name); // 小明
    
    var zhangsan = new Person('张三');
    console.log(zhangsan.name); // 张三
    

    当 this 碰到 return 时,如果返回值是一个对象,那么 this 指向的就是那个返回的对象,如果返回值不是一个对象那么 this 还是指向函数的实例

    function Person(name) {
      this.name = name;  
      return {}; // 返回 Object (函数除外)
    }
    var xiaoming = new Person('小明');
    console.log('name: ', xiaoming.name); // name: undefined
    
    function Person(name) {
      this.name = name;  
      return function() {};
    }
    var xiaoming = new Person('小明');
    console.log('name: ', xiaoming.name); // name:     (空值)
    
    function Person(name) {
      this.name = name;  
      return null; // 返回基本数据类型 Number, String, Boolean, Null, Undefined
    }
    var xiaoming = new Person('小明');
    console.log('name: ', xiaoming.name); // name: 小明
    

    扩展:箭头函数

    (待续...)


    参考文档:
    https://www.cnblogs.com/pssp/p/5216085.html
    https://blog.csdn.net/cjgeng88/article/details/79846670
    https://segmentfault.com/a/1190000019937964?utm_source=tag-newest

  • 相关阅读:
    面向接口程序设计思想实践
    Block Chain Learning Notes
    ECMAScript 6.0
    Etcd Learning Notes
    Travis CI Build Continuous Integration
    Markdown Learning Notes
    SPRING MICROSERVICES IN ACTION
    Java Interview Questions Summary
    Node.js Learning Notes
    Apache Thrift Learning Notes
  • 原文地址:https://www.cnblogs.com/uakora/p/12681646.html
Copyright © 2020-2023  润新知