另一种角度看待JavaScript中的this

本文尽量避免概念性的讲解,那样太抽象

所以下面以一些简单的例子,从易到难对this的用法总结

1.方法中的this会指向当前执行该方法的对象 如:

var name = "window"

var Tom = {
  name:"Tom";
  show:function(){
   console.log(this+":"+this.name)
  } 

} Tom.show(); //Tom

2.方法中的this不会指向声明它的对象 如下

var Bob={
  name:"Bob",
  show:function(){
  console.log(this+":"+this.name)
  }
}; 

var Tom={
  name:"Tom",
  show:Bob.show
}; 

Tom.show() ; //Tom

尽管console.log是Bob对象环境中声明的 ,但方法是由Tom对象调用执行

所以this总是会指向当前执行的对象,而不是声明的对象

其本质原因是:Bob.show方法赋值给Tom.show方法的时候不会把Bob对象也给绑定过去

下面是个将对象绑定过去的例子

3.嵌套对象中,this指向直接绑定它的对象

var Bob={
  name:"Bob",
  Tom:{
    name:"Tom",
    show:function(){console.log(this+":"+this.name)}
  }
}

Bob.Tom.show();  //Tom

4.用变量保存方法的执行结果,其执行对象仍然是Tom

var name="window";
var Tom={
  name:"Tom",
  show:function(){
  console.log(this+":"+this.name)
  }
};

var fun=Tom.show();
fun();              //Tom

此处fun所赋值的是Tom.show函数执行的结果,也就是Tom

上面的例子其实是下面所做对照的

5.用变量保存方法的内容,其执行对象是window

var name="window";
var Tom={
  name:"Tom",
  show:function(){
      console.log(this+":"+this.name)
  }
};

fun=Tom.show;
fun();              //Window

因为fun赋值的只是方法的内容,并没有绑定在Tom对象上,所以fun执行对象是window对象

6.若指明了调用方法的对象的话,this会指向调用其的对象 如下:

var name = "window";
var Bob= {
    name:"Bob",
    show:function(){console.log(this.name);}
    };

 var Tom= {name: "Tom"};
 Bob.show();                   //Bob
 Bob.show.apply();             //window
 Bob.show.apply(Tom);          //Tom

当然call()也差不多类似,apply和call用于指明由哪个对象去执行该方法

7.函数作为构造器时,this会指向新建的对象,如下

function Tom(name,age){
  this.name=name;
  this.age=age;
  this.getInfo=function(){
      console.log(this.name+" is "+this.age)
   }
}

var Bob = new Tom("Bob",45);

Bob.getInfo();  //Bob is 45

我们来点进阶的东西!!!

下面例子要解释的通 则需要两个重要的概念

延迟执行!

延迟调用!

8.将对象赋值给变量后,再调用方法,执行的对象仍然是Tom

var name="window";
var Tom={
  name:"Tom",
  show:function(){console.log(this.name)},
  wait:function(){
             var that=this;
             that.show();
         }
  };

Tom.wait();  //Tom

因为show绑定在that的对象里,而that的值是对象Tom,所以执行的对象指向了Tom

"将对象保存到变量,再去调用方法",这个过程称为延迟调用,若不明白没关系

接着往下看

9.在函数上下文中若没有指明执行方法的对象,那么会由全局对象window来执行

var name="window";
var Tom={
  name:"Tom",
  show:function(){console.log(this.name)},
  wait:function(){
             var fun=this.show;
             fun();
         }
  };

Tom.wait();  //window

fun赋值的是方法的内容,没有绑定于Tom对象里,因此执行的对象是window

上面的"把方法赋值给变量,再调用"这个过程可以看做延迟执行

延迟执行方法会导致该方法失去对象的绑定,导致对象由window执行执行

下面是一些延迟调用的例子

10.匿名函数的延迟

var name="window";
var Tom={
  name:"Tom",
  show:function(){console.log(this.name)},
  wait:function(){!function(call){call();}(this.show)}
  }

Tom.wait();    //Window

11.setTimeout、setInterval函数延迟
这里只以setTimeout为例子

var name="window";
var Tom={
  name:"Tom",
  show:function(){console.log(this.name)},
  wait:function(){setTimeout(this.show,1000)}
  }

Tom.wait();    //window

从上面两个例子可以得出:延迟执行会使得执行方法的对象更改为全局对象window

那么如何防止这种更改呢,我们尝试下面一招

12. 在延迟的环境下 尝试让Tom加班(对象也跟着延迟)

var name="window";
var Tom={
  name:"Tom",
  show:function(){console.log(this.name)},
  wait:function(){setTimeout(Tom.show,1000)}
}

Tom.wait();    //window 

上面中this就直接指明Tom,尝试让Tom加班,但是结果仍然为Window对象

因为Tom.show放在第一个参数里,就相当于这个方法被保存到一个变量里

然后经过延迟后再执行这个变量,而保存的时候依然没有绑定到对象Tom,因此执行的对象依然是window

这个和上面第9个例子是一个道理的。称为延迟执行,只不过这次的延迟执行是用了setTimeout来实现

那么难道没有办法避免延迟执行方法导致执行对象被更改了吗?非也!

让对象也跟着延迟就可以做到!如下

13.虽然延迟会导致方法的执行对象被更改为Window 但也有办法防止执行对象更改 如下

var name="window"
var  Tom ={
    name : "Tom",
    show : function(){console.log(this.name);},
    wait:  function(){
    var that=this;
    setTimeout(function(){that.show()},1000)}
          }

Tom.wait();    //Tom 

通过变量保存对象,再使用变量去调用方法,达到执行的对象也跟着延迟的效果

14.eval函数的延迟

对于eval比较特殊

在eval环境下,执行的对象就是当前作用域的对象 如下

var name="window";
var Bob={
  name:"Bob",
  showName: function(){ eval("console.log(this.name)"); }
  };

Bob.showName(); //Bob

15.eval函数的环境下,不会受到延迟而影响函数执行的对象

之所以eval特殊是因为eval不受延迟的影响

var name="window";
var that;
var Tom={
  name:"Tom",
  show:function(){console.log(this.name)},
  wait:function(){that=this;setTimeout("that.show()",1000)}
  }

Tom.wait();    //Tom

也许你会觉得上面的代码没有eval函数的身影

其实setTimeout函数的第一个参数就是eval环境

他会指向当前执行作用域的执行对象,忽略延迟方法延迟调用

点击下面可以看看田小计划对JavaScript的this是如何见解

http://www.cnblogs.com/wilber2013/p/4909505.html

能把上面例子都理解了,那么this是一把有利的刀!

当然如果不能理解,那么像闭包一样 尽量的少用!

时间: 2024-11-06 15:04:16

另一种角度看待JavaScript中的this的相关文章

用自然语言的角度理解JavaScript中的this关键字

转自:http://blog.leapoahead.com/2015/08/31/understanding-js-this-keyword/ 在编写JavaScript应用的时候,我们经常会使用this关键字.那么this关键字究竟是怎样工作的?它的设计有哪些好的地方,有哪些不好的地方?本文带大家全面系统地认识这个老朋友. 这里的小明是主语,如果没有这个主语,那么后面的代词『他』将毫无意义.有了主语,代词才有了可以指代的事物. 类比到JavaScript的世界中,我们在调用一个对象的方法的时候

如何理解并学习javascript中的面向对象(OOP) [转]

如果你想让你的javascript代码变得更加优美,性能更加卓越.或者,你想像jQuery的作者一样,写出属于自己优秀的类库(哪怕是基于 jquery的插件).那么,你请务必要学习javascript面向对象,否则你无法更灵活的使用javascript这门语言. 什么事闭包?到底什么是原型?(知道闭包和原型的,就算得上是javascript的高手了.但真正能够理解,并且灵活运用的人并不多)到底该如何学习javascript中的面向对象呢?在javascript这么语言正如日中天,相信不少人正在为

Javascript中函数调用和this的关系

例子先行: var myObject={ foo:"bar", func:function(){ var self=this; console.log("outerfunc:this.foo="+this.foo); console.log("outerfunc:self.foo="+self.foo); (function(){ console.log("innerfunc:this.foo="+this.foo); con

JavaScript中With 语句使用方法实例

内容导读: 有了 With 语句,在存取对象属性和方法时就不用重复指定参考对象,在 With 语句块中,凡是 JavaScript 不识别的属性和方法都和该语句块指定的对象有关.With 语句的语法格式如下所示: With Object { Statements } 对象指明了当语句组中对象缺省时的参考对象,这里我们用较为熟悉的 Document 对象对 With 语句举例.例如 当使用与 Document 对象有关的 write( )或 writeln( )方法时,往往使用如下形式: docu

【译】Javascript中的数据类型

这篇文章通过四种方式获取Javascript中的数据类型:通过隐藏的内置[[Class]]属性:通过typeof运算符:通过instanceof运算符:通过函数Array.isArray().我们也会看看原型对象的构造函数,可能会有意想不到的数据类型结果. [这篇文章是我在adobe发布的文章,我发布在这里只是为了存档.] 知识储备 在开始我们的话题之前,我们不得不复习一些所需的知识点 1.1 原始值和对象 Javascript中的数据,要么是原始值,要么是对象. 原始值.下面是原始值: und

JavaScript中创建对象的7种模式

ECMA-262把对象定义为:"无需属性的集合,其属性可以包含基本值.对象或者函数."严格来讲,这就相当于说明对象是一组没有特定顺序的值.对象的每个属性或方法都有一个名字,而每个名字都映射到一个值.正因为这样,我们可以把ECMAScript的对象想象成散列表:无非就是一组名对值,其中值可以是数据或函数. 创建自定义对象最简单的方式就是创建一个Object的实例,然后再为他添加属性和方法,如下所示: var person = new Object(); person.name = &qu

实现一个函数clone,使JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number.String.Object.Array.Boolean)进行值复制. 1 /** 对象克隆 2 * 支持基本数据类型及对象 3 * 递归方法 */ 4 function clone(obj) { 5 var o; 6 switch (typeof obj) { 7 case "undefined": 8 break; 9 case "string": o = obj + &q

JavaScript中的三种弹出对话框

JavaScript中的三种弹出对话框 *****本文来自互联网****** 学习过js的小伙伴会发现,我们在一些实例中用到了alert()方法.prompt()方法.prompt()方法,他们都是在屏幕上弹出一个对话框,并且在上面显示括号内的内容,使用这种方法使得页面的交互性更精彩,实际上我们经常会在进行网页浏览时简单这种类型的对话框,在用户与应用程序进行双向交流时,经常要用到对话框.avascript的三种对话框是通过调用window对象的三个方法alert(),confirm()和prom

在JavaScript中判断整型的N种方法

整数类型(Integer)在JavaScript经常会导致一些奇怪的问题.在ECMAScript的规范中,他们只存在于概念中: 所有的数字都是浮点数,并且整数只是没有一组没有小数的数字. 在这篇博客中,我会解释如何去检查某个值是否为整型. ECMAScript 5 在ES5中有很多方法你可以使用.有时侯,你可能想用自己的方法:一个isInteger(x)的函数,如果是整型返回true,否则返回false. 让我们看看一些例子. 通过余数检查 你可以使用余数运算(%),将一个数字按1求余,看看余数