闭包中this的指代,以及四种函数调用中this的指代

    Q:

  1. // (1)这里this指代什么?
  2. function a(){
  3.      // (2)这里this指代什么?
  4.      var c = 2;
  5.      function b(){
  6.          // (3)这里呢?this又指代什么?
  7.          return c;
  8.     }
  9.      return b;
  10. }
  11. a()();  //调用a()函数会返回一个b函数,a()()表示当返回b函数之后立即执行。
A:(1)处指window,(2)处指的是a,(3)处指的是b。
面试官:嗯?是吗?你不好好想想吗?

我的内心:啊啊啊,哪里有洞。。。我是有多菜。

是,你没有看错,我确实是这么回答的,很可笑啊,我一直都觉得这真的是耻辱啊,我想我一辈子都不会忘记。不过,这个面试官很nice,给我道出了正确答案,还告诉我为什么。这场面试下来,我所有的自信心都被摧毁得破碎不堪,但它却是我最有收获的一次面试,也成为我前端路上的一次转折点。
        正确的应该是:这三处均指的是window对象。

       This,何意?这,这里,这个。在JavaScript中,它是关键字,既不是变量,也不是属性名,所以它是不允许被赋值的。那它是什么关键字呢?在JavaScript中,它指的是函数调用的上下文(context)。
        根据ECMAScript3和非严格的ECMAScript5对函数调用的规定,this的值是全局对象。在严格模式下,则是undefined。和变量不同,关键字没有作用域的限制,嵌套函数(闭包)不会从调用它的函数中继承this。若想访问外部函数的this值,需要将它的值保存在一个变量里,这个变量和内部函数都同在一个作用域内。可看下面代码:

  1. var o = {
  2.      m: function(){
  3. var self = this;
  4. console.log( this === o); // true, this就是这个对象o
  5. f();
  6. // 定义一个嵌套函数f()
  7. function f(){
  8.      console.log( this === o); // false,this的值是全局对象或者undefined
  9.      console.log(self === o); // true, self值外部函数的this值
  10. }
  11.     }
  12. };
  13. o.m();

       this是在运行时基于函数的执行环境绑定的。在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过,随着函数使用场合不同,this的值可能发生变化。我们知道,在JavaScript中,调用函数有4种方式:

  • 普通的函数调用
  • 作为对象的方法调用
  • 作为构造函数调用
  • 通过它们的call()和apply()间接调用

那么就从它的调用方式简单分析一下,如有错误,烦请批评指正:

(1)作为函数

这是最通常的函数用法,属于全局性调用,因此this等于全局对象。

  1. function f(){
  2.      window.x = 1;
  3.      console.log( this.x);
  4. }
  5. f(); // 1

对代码做些改变再看,

  1. var x = 1;
  2. function f(){
  3.      console.log( this.x);
  4. }
  5. f(); // 1
  6. console.log( window.x); // 1

window.x与this.x值相等。再变一下,

  1. var x = 1;
  2. function f(){
  3.      this.x = -1;
  4. console.log( this.x);
  5. }
  6. f(); // -1
  7. console.log(x); // -1

在f()中给this.x赋值为-1,结果x的值跟着改变为-1,所以this等于全局对象。

(2)作为方法

当函数作为某个对象的方法调用时,这时this的值就是这个对象。

  1. function f(){
  2.      console.log( this.x);
  3. }
  4. var o = {
  5.      x: -1,
  6.      m: f
  7. };
  8. o.m(); // -1
  9. o.x = 1;
  10. o.m(); // 1

对象的属性值改变,f()里面this.x跟着改变。可以在f()里面打印一下this,看看结果呢!

(3)作为构造函数

作为构造函数调用时,使用new关键字初始化一个实例对象,这时this等于这个实例对象。

  1. function f(){
  2.      this.name = "zrn";
  3. }
  4. var o = new f();
  5. console.log(o.name); // "zrn"

运行结果为”zrn”,表示这并非全局对象。变一下代码,

  1. var name = "window";
  2. function f(){
  3.      this.name = "zrn";
  4. }
  5. var o = new f();
  6. console.log(o.name); // "zrn"
  7. console.log(name); // "window"

name的值互不干涉。

(4)通过call()或者apply()调用

call()和apply()的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this的值。第一个参数(context)是函数运行的作用域,第二个参数是参数数组(argArr),不过使用call()时,要将这些参数逐个列举出来。如果未传递context,则context是全局对象(啊,说的有点多了)。

  1. var name = "window";
  2. function f(){
  3.      console.log( this.name);
  4. }
  5. var o = { name: "zrn"};
  6. f.call(); // "window", this指的是window
  7. f.apply(o); // "zrn", this指的是对象o
结束语:以上就是我对this的基础理解了,不过理解与正确地使用又差一大截,所以只有不断地实践,不断地积累,才能够对this的使用信手拈来,达到炉火纯青的地步,所以,come on!
ps: call()和apply()方法是很强大的方法,期待更深入的学习它们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值