zoukankan      html  css  js  c++  java
  • 关于js中this的指向问题与如何修改this的指向

    先上结论:
      1、如果this出现在函数内,那么this永远指向调用这个方法的对象。
      2、如果this不是出现在函数内,即出现在全局作用域或者出现在一个对象内部,那么他永远指向全局对象window。

    1、这里先求证结论的第二点
      在全局作用域下,所有的全局变量和方法都是挂载到window这个全局对象下。(一般我们使用a对象的b属性时都是以 a.b 的形式来使用,但是为了书写方便,在使用全局变量和方法时JS允许我们可以省掉window。)
      从下图我们可以看出,在全局作用域下this和window都是同一个东西。

    var b = 0;
    function f(){
    console.log(this);
    }
    window.b === b; // true
    window.f === f // true
    this === window // true
    1
    2
    3
    4
    5
    6
    7
      我们再来看在全局作用域下的一个自定义对象内部的his指向。

    var name = "a";
    var obj = {
    name: "b",
    name1: this.name
    }
    console.log(obj.name1) // 输出a
    1
    2
    3
    4
    5
    6
      相信大家这里有点疑惑了,欸?不对吧?按道理this不是应该指向obj吗?为什么还是指向window,我们再来看一个。

    var name = "a";
    var obj = {
    name: "b",
    obj1: {
    name: "c",
    name1: this.name
    }
    }
    console.log(obj.obj1.name1) // 输出a
    1
    2
    3
    4
    5
    6
    7
    8
    9
      看到这里大家应该知道了,不管嵌套多少层对象,只要你的this不在一个方法内。你的this始终指向全局对象window。

    2、然后求证结论的第一点
      这里有人会提出疑问,这里UP说this永远指向调用这个方法的对象。那么我直接执行这个方法会如何?没有对象调用这个方法时,UP的说法前提都没有,自然是错误的。
      这里大家不要忘了,我之前说了,全局作用域下的方法都是挂载到window对象上的,并且调用全局方法时,可以省略window,所以你直接执性一个方法,其实是window对象在调用这个方法。我们只需要求证直接执方法时方法内部的this与window是不是同一个东西即可证明我的说法是否有错误。
      下面这段代码可以看出我的结论没有错误

    function f(){
    console.log(this)
    console.log(this === window)
    }
    f() //打印出Window对象,true
    1
    2
    3
    4
    5
      接下来看这个

    var name = "a";
    function f(){
    console.log(this.name)
    }
    var obj = {
    name: "b",
    f: f,
    foo: function(){
    console.log(this.name);
    }
    }
    obj.f() //打印出b
    obj.foo() //打印出b
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
      可以看出来了,此时不管是全局定义的函数还是对象内部定义的函数,它的this始终指向该方法的调用对象。
    (我猜上面我说对象内部的this都指向window,有人会举上述类似的例子反驳我说,对象内部方法this指向obj啊,UP真垃圾,关了,看下一篇博文。注意哦,我上面的结论是有前提的,this不在一个方法内,this才指向window。这里如果被我说中,请给点个赞或者评论一下哦!!!感谢)
      我们再来看一个难的。

    var name = "a";
    var obj = {
    name: "b",
    foo: function(){
    return function(){
    console.log(this.name);
    }
    }
    }
    // 注意这里foo返回一个方法,要让返回的这个方法执行,必须要再加一个()
    obj.foo()(); // 输出a
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
      这里又有人疑惑了,不是说好的指向调用的对象obj吗?怎么指向window了。这里注意了,foo方法返回另一个方法,此时obj.foo()已经执行完了,再执行这个函数,相当于在全局直接调用这个方法。此时调用它的还是obj吗?不是,此时执行这个方法的是window。

      此时有人可能会说构造函数里有this,但是在创建对象时构造函数既没有直接执形,也没有被对象调用,而是采用new className()的形式创建对象,那么他里面的this是怎么指向新创建的对象的?

    function Animal(name){
    this.name = name;
    }
    var cat = new Animal("cat");
    1
    2
    3
    4
      这是因为用new关键字创建对象时,new执行了一些暗操作,其中有一个操作就是修改构造函数this的指向,使this指向新创建的对象。
      new 关键字做了大概如下的暗操作。详细我就不讲了,大家可以看我的博客 js创建对象时new关键字到底做了哪些暗操作? 来了解更多细节。

    var obj = {};
    // 这里new会显示修改Animal的this指向
    Animal.call(obj);
    obj.__proto__ = Animal.prototype;
    return obj;
    1
    2
    3
    4
    5
      Animal.call(obj)就是显示修改this指向的操作。这里我简单说下显示修改函数内this指向的几种方式,使其this指向我们想要的对象。
    第一种
      Function.prototype.call(thisArg, …args)
        第一个参数是你期望this指向的那个对象,其他参数是你执行这个函数所需的参数
        call方法一旦调用,调用call方法的函数立刻执行。
      Animal.call(obj);
    第二种
      Function.prototype.apply(thisArg, [argsArray])
        第一个参数是你期望this指向的那个对象,第二个参数是一个数组,里面是你执行这个函数所需的参数
        apply方法一旦调用,调用apply方法的函数立刻执行。
      Animal.apply(obj);
    第三种
      Function.prototype.bind(thisArg, …args)
        第一个参数是你期望this指向的那个对象,其他参数是你执行这个函数所需的参数
        bind方法不会立刻执行,而是拷贝一份这个函数,然后修改this的指向后,最后将这个函数返回出去。
      var copy = Animal.bind(obj);

    最后总结之前我再谈一点我的理解
      其实我们可以把我开头总结的两条结论,归为一条,那就是this永远指向调用this所属的方法的那个对象。
      为什么可以这么说呢?因为我觉得全局作用域是一个方法的内部作用域,而调用这个方法的对象正是window,所以全局作用域的this始终指向window,js为了开发书写方便,把这些条条框框都去掉了。

    var window = {
    f: function(){
    // 这里是我们开始书写代码的地方
    }
    }
    window.f();
    1
    2
    3
    4
    5
    6
      所以this的指向问题可以总结为:this永远指向调用this所属的方法的那个对象。
      但是这个不好理解,我也不太确定它内部到底是如何去做的,所以这里只是我的一种猜测。大家还是照我开头那样总结的this指向去解决开发中this的指向问题。

    总结:
    一、this的指向问题
      1、如果this出现在函数内,那么this永远指向调用这个方法的对象。
      2、如果this不是出现在函数内,即出现在全局作用域或者出现在一个对象内部,那么他永远指向全局对象window。
    二、显示修改this指向的方法
      1、call()
      2、apply()
      3、bind()
    ————————————————
    版权声明:本文为CSDN博主「Vgbire」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/RkHker/article/details/104583899

  • 相关阅读:
    2.22
    LG P7077 函数调用
    2020/10/30 模拟赛 序列
    2020/10/27 模拟赛 数列
    2020/10/23 模拟赛 chip
    2020/10/23 模拟赛 escape
    2020/10/23 模拟赛 center
    LOJ#6581. 「ICPC World Finals 2019」断头路探测者
    LG P1587 [NOI2016]循环之美
    LG P4156 [WC2016]论战捆竹竿
  • 原文地址:https://www.cnblogs.com/dillonmei/p/12569085.html
Copyright © 2011-2022 走看看