zoukankan      html  css  js  c++  java
  • js this问题和es6箭头函数this问题

    JS中this的四种用法

    1.在一般函数方法中使用 this 指代全局对象

    function test(){
        this.x = 1;
        alert(this.x);
      }
      test(); //1

    2.作为对象方法调用,this 指代上级对象

    function test(){
      alert(this.x);
    }
    var o = {};
    o.x = 1;
    o.m = test;
    o.m(); // 1
    

    3.作为构造函数调用,this 指代new 出的对象

     function test(){
        this.x = 1;
      }
      var o = new test();
      alert(o.x); // 1
        //运行结果为1。为了表明这时this不是全局对象,我对代码做一些改变:
      var x = 2;
      function test(){
        this.x = 1;
      }
      var o = new test();
      alert(x); //2

    4.apply 调用 ,apply方法作用是改变函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象,this指代第一个参数

      var x = 0;
      function test(){
        alert(this.x);
      }
      var o={};
      o.x = 1;
      o.m = test;
      o.m.apply(); //0
    //apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。如果把最后一行代码修改为
    
      o.m.apply(o); //1

    ES6中箭头函数与普通函数this的区别

     

    普通函数中的this:

    1. this总是代表它的直接调用者, 例如 obj.func ,那么func中的this就是obj

    2.在默认情况(非严格模式下,未使用 'use strict'),没找到直接调用者,则this指的是 window

    3.在严格模式下,没有直接调用者的函数中的this是 undefined

    4.使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象

    箭头函数中的this

    默认指向在定义它时,它所处的对象,而不是执行时的对象, 定义它的时候,可能环境是window(即继承父级的this);

    下面通过一些例子来研究一下 this的一些使用场景

    示例1

    <script>
      var obj = {
        say: function () {
          setTimeout(function () {
            console.log(this)
          });
        }
      }
      obj.say();
    </script>

    结果是:window

    匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window

    问题: 如果想要在setTimeout中使用这个对象的引用呢?

    用一个 变量提前把正确的 this引用保存 起来, 我们通常使用that = this, 或者 _this = this来保存我们需要的this指针!

    <script>
      var obj = {
        func: function() {},
        say: function () {
          var that = this;   //此时的this就是obj对象
          setTimeout(function () {
            console.log(this)
            that.func()
          });
        }
      }
      obj.say();
    </script>

    示例2

    window.val = 1;
    var obj = {
      val: 2,
      dbl: function () {
        this.val *= 2;
        val *= 2;
        console.log(val);
        console.log(this.val);
      }
    };
    // 说出下面的输出结果
    obj.dbl();
    var func = obj.dbl;
    func();

    结果是:2  4  8  8

    <1> 12行代码调用

    val变量在没有指定对象前缀,默认从函数中找,找不到则从window中找全局变量

    即 val *=2 就是 window.val *= 2

    this.val默认指的是 obj.val ;因为 dbl()第一次被obj直接调用

    <2>14行代码调用

    func() 没有任何前缀,类似于全局函数,即  window.func调用,所以

    第二次调用的时候, this指的是window, val指的是window.val

    第二次的结果受第一次的影响

    示例3.在严格模式下的this

    <script>
      function test() {
        'use strict';
        console.log(this);
      }
      test();
    </script>

    结果是:undefined

    示例4.箭头函数中的this

    <script>
      var obj = {
        say: function () {
          setTimeout(() => {
            console.log(this)
          });
        }
      }
      obj.say(); // obj
    </script>

     此时的this是定义它的对象,即继承父级的this,父级中的this指的是obj,而非window

    示例5

    <script>
      var obj = {
        say: function () {
          var f1 = () => {
            console.log(this); // obj
            setTimeout(() => {
              console.log(this); // obj
            })
          }
          f1();
        }
      }
      obj.say()
    </script>

    结果:都是obj

    f1继承父级this指代的obj,不管f1有多层箭头函数嵌套,都是obj.

    示例6

    <script>
      var obj = {
        say: function () {
          var f1 = function () {
            console.log(this);    // window, f1调用时,没有宿主对象,默认是window
            setTimeout(() => {
              console.log(this); // window
            })
          };
          f1();
        }
      }
      obj.say()
    </script>

    结果:window,window

    第一个this:f1调用时没有宿主对象,默认是window

    第二个this:继承父级的this,父级的this指代的是window

    关于this指向问题的讨论一直是学习js不可忽视的重要部分,那些一个又一个围绕this挖的笔试坑,仿佛永远也填不完

     
    var obj={
     
    fn:function(){
     
    console.log(this);
     
    }
     
    } 
    obj.fn();//object

    以上这段代码是再浅显不过的this指向问题,也就是谁调用的函数,函数体中的this就指向谁

    再看下面这段

    var obj={
     
    fn:function(){
     
    setTimeout(function(){
     
    console.log(this);
     
    });
     
    }
    } 
    obj.fn();//window

    这次this指向了最外层的window对象,为什么呢,还是那个道理,这次this出现在全局函数setTImeout()中的匿名函数里,并没有某个对象进行显示调用,所以this指向window对象

    假如我们在这里使用箭头函数呢

     
    var obj={
     
    fn:function(){
     
    setTimeout(() => {
     
    console.log(this);
     
    });
     
    }
     
    }
     
    obj.fn();//object

    this又指向函数的宿主对象了

    为了更加清楚的对比一般函数和箭头函数this指向的区别,我们给对象添加变量

     
    var obj={
     
    num:3,
     
    fn:function(){
     
    setTimeout(function(){
     
    console.log(this.num);
     
    });
     
    }
     
    }
     
    obj.fn();//undefined
     
    //............................................................
     
    var obj1={
     
    num:4,
     
    fn:function(){
     
    setTimeout(() => {
     
    console.log(this.num);
     
    });
     
    }
     
    }
     
    obj1.fn();//4

    如上代码,在没有使用箭头函数的情况下,this指向了window(匿名函数,没有调用的宿主对象),而window对象并没有num属性(num属性在obj中定义),而在使用箭头函数的情况下,this的指向却对象obj1,自然可以输出obj1中定义的属性num。

    接下来看更复杂的情况

    多层嵌套的箭头函数

     
    var obj1={
     
    num:4,
     
    fn:function(){
     
    var f=() => { //object,也就是指obj1
     
    console.log(this);
     
    setTimeout(() => {
     
    console.log(this);// //object,也就是指obj1
     
    });
     
    }
     
    f();
     
    }
     
    }
     
    obj1.fn();

    假如我们改动两层箭头函数的其中一处,看会出现什么结果

     
    var obj1={
     
    num:4,
     
    fn:function(){
     
    var f=function(){
     
    console.log(this); //window,因为函数f定义后并没有对象调用,this直接绑定到最外层的window对象
     
    setTimeout(() => {
     
    console.log(this);//window,外层this绑定到了window,内层也相当于定义在window层(全局环境)
     
    });
     
    }
     
    f();
     
    }
     
    }
     
    obj1.fn();

    好,接下来改变另一处

     
    var obj1={
     
    num:4,
     
    fn:function(){
     
    var f=() => {
     
    console.log(this); //object,f()定义在obj1对象中,this就指向obj1,这就是箭头函数this指向的关键
     
    setTimeout(function() {
     
    console.log(this);//window,非箭头函数的情况下还是要看宿主对象是谁,如果没有被对象调用,函数体中的this就绑定的window上
     
    });
     
    }
     
    f();
     
    }
     
    }
     
    obj1.fn();


    总结:

    1.箭头函数的this绑定看的是this所在的函数定义在哪个对象下,绑定到哪个对象则this就指向哪个对象

    2.如果有对象嵌套的情况,则this绑定到最近的一层对象上

  • 相关阅读:
    Java进阶7并发优化4——JDK并发数据结构
    Java 进阶7 并行优化 JDK多任务执行框架技术
    Java进阶7 并发优化2 并行程序设计模式
    Java 进阶7 并发优化 1 并行程序的设计模式
    Java 进阶6 异常处理的陷阱
    Algorithm3: 获得一个int数中二进制位为1 的个数
    Algorithm2: 重复查过半数的元素
    Algorithm1: 全排列
    Java进阶5 面向对象的陷阱
    Java进阶2 数组内存和对象的内存管理知识
  • 原文地址:https://www.cnblogs.com/yaphetsfang/p/9305485.html
Copyright © 2011-2022 走看看