专栏首页yaphetsfangjs this问题和es6箭头函数this问题

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绑定到最近的一层对象上

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Invoke 和 BeginInvoke 的区别

    在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate

    yaphetsfang
  • @Component和@Bean以及@Autowired、@Resource

      Spring用xml配置文件的时候(不知道阅读这篇文章的你用没用过,我用过一段时间,那是黑暗伤痛的回忆QQQ),一个xml配置文件里面有很多个bean。类似...

    yaphetsfang
  • Asp.Net Mvc表单提交(批量提交)

    Asp.Net Mvc中Action的参数可以自动接收和反序列化form表单的值,

    yaphetsfang
  • ExtJs+WCF+LINQ实现分页Grid

    上篇文章《用ExtJs+Linq+Wcf打造简单grid 》,这个网格控件不带分页,本文在上文的基础上添加分页功能,文中会着重介绍如何在用LINQ返回分页数据,...

    菩提树下的杨过
  • 你不知道的 this 指向优先级

    本文会以详细讲解一道 字节面试题 的方式,循序渐进完全搞定 js 中 this 指向优先级的问题。 ⛹‍♂⛹‍♂ js 中的 this 指向问题应该是一个讨论了...

    一只图雀
  • 使用Box2D实现物体的碰撞检测和实现自动化背景布置

    我们本节要实现的是,当用户把小球投入篮框,如果小球能从篮框中间漏下去,那么就可以算得分。这就需要我们进行碰撞检测,Box2D给我们提供良好机制能实现这点功能。我...

    望月从良
  • Application Firewall Design

    Application Firewall Design Web Application Firewall, 7layer Firewall ---- 目录 1....

    netkiller old
  • Phaser.js之简单的跑酷游戏

    源码(详细源码图片资源可点击文章下方或屏幕右上方的github链接进行clone)

    ProsperLee
  • 用HTML5-Canvas 写一个桌球游戏!

    这只是一个简单的DEMO。游戏性、游戏规则没怎么考虑,如果有兴趣细化的朋友可以细化一下,比如细化一下规则,游戏开关,加个声音,细化一下进球检测,更严谨甚至可以去...

    用户5997198
  • this,call,apply,bind(万字长文)

    大家好啊,我是吒儿?,每天努力一点点?,就能升职加薪?当上总经理出任CEO迎娶白富美走上人生巅峰?,想想还有点小激动呢?。

    达达前端

扫码关注云+社区

领取腾讯云代金券