• this关键字的理解与总结


    1.this关键字的含义

    简单说,this就是属性或方法“当前”所在的对象。

    this都有一个共同点:它总是返回一个对象。

    举例:

    var A = {
      name: '张三',
      describe: function () {
        return '姓名:'+ this.name;
      }
    };
    A.describe();
    // '姓名:张三'
    由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。
    var A = {
      name: '张三',
      describe: function () {
        return '姓名:'+ this.name;
      }
    };
    
    var B = {
      name: '李四'
    };
    
    B.describe = A.describe;
    B.describe()
    // "姓名:李四"

    重构如下

    function f() {
      return '姓名:'+ this.name;
    }
    
    var A = {
      name: '张三',
      describe: f
    };
    
    var B = {
      name: '李四',
      describe: f
    };
    
    A.describe() // "姓名:张三"
    B.describe() // "姓名:李四"

    只要函数被赋给另一个变量,this的指向就会变。

    var A = {
      name: '张三',
      describe: function () {
        return '姓名:'+ this.name;
      }
    };
    
    var name = '李四';
    var f = A.describe;
    f() // "姓名:李四"

    A.describe被赋值给变量f,内部的this就会指向f运行时所在的对象(本例是顶层对象);

    一切皆对象,运行环境也是对象,所以函数都是在某个对象之中运行,this就是函数运行时所在的对象(环境)。

    2.this的实质

    var obj = { foo:  5 };

    原始的对象以字典结构保存;

    引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

    {
      foo: {
        [[value]]: 5
        [[writable]]: true
        [[enumerable]]: true
        [[configurable]]: true
      }
    }
    属性值是一个函数的情况
    var obj = { foo: function () {} };
    {
      foo: {
        [[value]]: 函数的地址
        ...
      }
    }

    由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。

    它的设计目的就是在函数体内部,指代函数当前的运行环境。

    3.使用场合

    (1)全局环境

    全局环境使用this,它指的就是顶层对象window

    this === window // true

    (2)构造函数

    构造函数中的this,指的是实例对象。

    var Obj = function (p) {
      this.p = p;
    };
    var o = new Obj('Hello World!');
    o.p // "Hello World!"
    
    

    (3)对象的方法

    如果对象的方法里面包含thisthis的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变this的指向。

    如果this所在的方法不在对象的第一层,这时this只是指向当前一层的对象,而不会继承更上面的层。

    
    
    var a = {
      p: 'Hello',
      b: {
        m: function() {
          console.log(this.p);
        }
      }
    };
    
    a.b.m() // undefined
    因此,实际执行是下面这个代码
    var b = {
      m: function() {
       console.log(this.p);
      }
    };
    
    var a = {
      p: 'Hello',
      b: b
    };
    
    (a.b).m() // 等同于 b.m()
    想要达到预期效果是
    var a = {
      b: {
        m: function() {
          console.log(this.p);
        },
        p: 'Hello'
      }
    };
    
    

    如果这时将嵌套对象内部的方法赋值给一个变量,this依然会指向全局对象。

    var a = {
      b: {
        m: function() {
          console.log(this.p);
        },
        p: 'Hello'
      }
    };
    
    var hello = a.b.m;
    hello() // undefined

    4. 1)避免多层this

    var o = {
      f1: function () {
        console.log(this);
        var f2 = function () {
          console.log(this);
        }();
      }
    }
    
    o.f1()
    // Object
    // Window

    实际执行如下

    var temp = function () {
      console.log(this);
    };
    
    var o = {
      f1: function () {
        console.log(this);
        var f2 = temp();
      }
    }

    一个解决方法是在第二层改用一个指向外层this的变量。

    that,固定指向外层的this,然后在内层使用that,就不会发生this指向的改变。

    var o = {
      f1: function() {
        console.log(this);
        var that = this;
        var f2 = function() {
          console.log(that);
        }();
      }
    }
    
    o.f1()
    // Object
    // Object

    4. 2)避免数组处理方法中的this

    var o = {
      v: 'hello',
      p: [ 'a1', 'a2' ],
      f: function f() {
        this.p.forEach(function (item) {
          console.log(this.v + ' ' + item);
        });
      }
    }
    
    o.f()
    // undefined a1
    // undefined a2

    解决方法

    1.使用中间变量固定this;

    2.另一种方法是将this当作foreach方法的第二个参数,固定它的运行环境。

    
    
    var o = {
      v: 'hello',
      p: [ 'a1', 'a2' ],
      f: function f() {
        this.p.forEach(function (item) {
          console.log(this.v + ' ' + item);
        }, this);
      }
    }
    
    o.f()
    // hello a1
    // hello a2
    
    

    3.避免在回调函数中使用this;

    var o = new Object();
    o.f = function () {
      console.log(this === o);
    }
    
    // jQuery 的写法
    $('#button').on('click', o.f);

    上面代码中,点击按钮以后,控制台会显示false。原因是此时this不再指向o对象,而是指向按钮的 DOM 对象,因为f方法是在按钮对象的环境中被调用的。

    为了解决这个问题,可以采用下面的一些方法对this进行绑定,也就是使得this固定指向某个对象,减少不确定性。

    1.Function.prototype.call()

    call方法的参数,应该是一个对象。如果参数为空、nullundefined,则默认传入全局对象。

    2.Function.prototype.apply()

    3.Function.prototype.bind()

    var counter = {
      count: 0,
      inc: function () {
        this.count++;
      }
    };
    
    var func = counter.inc.bind(counter);
    func();
    counter.count // 1

    如果bind方法的第一个参数是nullundefined,等于将this绑定到全局对象,函数运行时this指向顶层对象(浏览器为window);

    function add(x, y) {
      return x + y;
    }
    
    var plus5 = add.bind(null, 5);
    plus5(10) // 15
     
     
     
     
     
  • 相关阅读:
    MongoDB笔记
    mysql笔记
    08-下载中间件
    ubuntu1804安装pycharm2018.3.x
    02-CSS基础
    14-eval 函数
    13-文件
    12-模块和包
    11-异常
    有关dir和 unittest
  • 原文地址:https://www.cnblogs.com/jiaqi1719/p/10111875.html
Copyright © 2020-2023  润新知