javascript中的this含义非常丰富,它可以是全局对象,当前对象或者是任意对象,这都取决于函数的调用方式。函数有以下几种调用方式:作为对象方法调用、作为函数调用、作为构造函数调用、apply或call调用。

对象方法调用

作为对象方法调用的时候,this会被绑定到该对象。

  1. var point = {
  2. x : 0,
  3. y : 0,
  4. moveTo : function(x, y) {
  5. this.x = this.x + x;
  6. this.y = this.y + y;
  7. }
  8. };
  9.  
  10. point.moveTo(1, 1)//this 绑定到当前对象,即 point 对象

这里我想强调一点内容,就是this是在函数执行的时候去获取对应的值,而不是函数定义时。即使是对象方法调用,如果该方法的函数属性以函数名的形式传入别的作用域,也会改变this的指向。我举一个例子:

  1. var a = {
  2. aa : 0,
  3. bb : 0,
  4. fun : function(x,y){
  5. this.aa = this.aa + x;
  6. this.bb = this.bb + y;
  7. }
  8. };
  9. var aa = 1;
  10. var b = {
  11. aa:0,
  12. bb:0,
  13. fun : function(){return this.aa;}
  14. }
  15. a.fun(3,2);
  16. document.write(a.aa);//3,this指向对象本身
  17. document.write(b.fun());//0,this指向对象本身
  18. (function(aa){//注意传入的是函数,而不是函数执行的结果
  19. var c = aa();
  20. document.write(c);//1 , 由于fun在该处执行,导致this不再指向对象本身,而是这里的window
  21. })(b.fun);

这样就明白了吧。这是一个容易混淆的地方。

函数调用

函数也可以直接被调用,这个时候this被绑定到了全局对象。

  1. var x = 1;
  2.   function test(){
  3.     this.x = 0;
  4.   }
  5.   test();
  6.   alert(x);

但这样就会出现一些问题,就是在函数内部定义的函数,其this也会指向全局,而和我们希望的恰恰相反。代码如下:

  1. var point = {
  2. x : 0,
  3. y : 0,
  4. moveTo : function(x, y) {
  5. // 内部函数
  6. var moveX = function(x) {
  7. this.x = x;//this 绑定到了全局
  8. };
  9. // 内部函数
  10. var moveY = function(y) {
  11. this.y = y;//this 绑定到了全局
  12. };
  13.  
  14. moveX(x);
  15. moveY(y);
  16. }
  17. };
  18. point.moveTo(1, 1);
  19. point.x; //==>0
  20. point.y; //==>0
  21. x; //==>1
  22. y; //==>1

我们会发现不但我们希望的移动呢效果没有完成,反而会多出两个全局变量。那么如何解决呢?只要要进入函数中的函数时将this保存到一个变量中,再运用该变量即可。代码如下:

  1. var point = {
  2. x : 0,
  3. y : 0,
  4. moveTo : function(x, y) {
  5. var that = this;
  6. // 内部函数
  7. var moveX = function(x) {
  8. that.x = x;
  9. };
  10. // 内部函数
  11. var moveY = function(y) {
  12. that.y = y;
  13. }
  14. moveX(x);
  15. moveY(y);
  16. }
  17. };
  18. point.moveTo(1, 1);
  19. point.x; //==>1
  20. point.y; //==>1

构造函数调用

在javascript中自己创建构造函数时可以利用this来指向新创建的对象上。这样就可以避免函数中的this指向全局了。

  1. var x = 2;
  2.   function test(){
  3.     this.x = 1;
  4.   }
  5.   var o = new test();
  6.   alert(x);

apply或call调用

这两个方法可以切换函数执行的上下文环境,也就是改变this绑定的对象。apply和call比较类似,区别在于传入参数时一个要求是数组,一个要求是分开传入。所以我们以apply为例:

  1. <pre name="code" class="html">var name = "window";
  2.  
  3. var someone = {
  4. name: "Bob",
  5. showName: function(){
  6. alert(this.name);
  7. }
  8. };
  9.  
  10. var other = {
  11. name: "Tom"
  12. };
  13.  
  14. someone.showName(); //Bob
  15. someone.showName.apply(); //window
  16. someone.showName.apply(other); //Tom

可以看到,正常访问对象中方法时,this指向对象。使用了apply后,apply无参数时,this的当前对象是全局,apply有参数时,this的当前对象就是该参数。

箭头函数调用

这里需要补充一点内容,就是在下一代javascript标准ES6中的箭头函数的 this始终指向函数定义时的 this,而非执行时。我们通过一个例子来理解:

  1. var o = {
  2. x : 1,
  3. func : function() { console.log(this.x) },
  4. test : function() {
  5. setTimeout(function() {
  6. this.func();
  7. }, 100);
  8. }
  9. };
  10.  
  11. o.test(); // TypeError : this.func is not a function

上面的代码会出现错误,因为this的指向从o变为了全局。我们需要修改上面的代码如下:

  1. var o = {
  2. x : 1,
  3. func : function() { console.log(this.x) },
  4. test : function() {
  5. var _this = this;
  6. setTimeout(function() {
  7. _this.func();
  8. }, 100);
  9. }
  10. };
  11.  
  12. o.test();

通过使用外部事先保存的this就行了。这里就可以利用到箭头函数了,我们刚才说过,箭头函数的 this始终指向函数定义时的 this,而非执行时。所以我们将上面的代码修改如下:

  1. var o = {
  2. x : 1,
  3. func : function() { console.log(this.x) },
  4. test : function() {
  5. setTimeout(() => { this.func() }, 100);
  6. }
  7. };
  8.  
  9. o.test();

这回this就指向o了,我们还需要注意一点的就是这个this是不会改变指向对象的,我们知道call和apply可以改变this的指向,但是在箭头函数中是无效的。

  1. var x = 1,
  2. o = {
  3. x : 10,
  4. test : () => this.x
  5. };
  6.  
  7. o.test();
  8. o.test.call(o); // 依然是1

这样就可以明白各种情况下this绑定对象的区别了。

JavaScript之this指针深入详解的更多相关文章

  1. javascript常用经典算法实例详解

    javascript常用经典算法实例详解 这篇文章主要介绍了javascript常用算法,结合实例形式较为详细的分析总结了JavaScript中常见的各种排序算法以及堆.栈.链表等数据结构的相关实现与 ...

  2. javascript中=、==、===区别详解

    javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...

  3. Javascript 调试利器 Firebug使用详解

    Javascript 调试利器 Firebug使用详解 有时候,为了更清楚方便的查看输出信息,我们可能需要将一些调试信息进行分组输出,那么可以使用console.group来对信息进行分组,在组信息输 ...

  4. JavaScript中return的用法详解

    JavaScript中return的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 t ...

  5. javascript 中合并排序算法 详解

    javascript 中合并排序算法 详解 我会通过程序的执行过程来给大家合并排序是如何排序的...  合并排序代码如下: <script type="text/javascript& ...

  6. javascript中的this作用域详解

    javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...

  7. JavaScript中this的用法详解

    JavaScript中this的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 thi ...

  8. 高性能JavaScript模板引擎实现原理详解

    这篇文章主要介绍了JavaScript模板引擎实现原理详解,本文着重讲解artTemplate模板的实现原理,它采用预编译方式让性能有了质的飞跃,是其它知名模板引擎的25.32 倍,需要的朋友可以参考 ...

  9. JavaScript对象的property属性详解

    JavaScript对象的property属性详解:https://www.jb51.net/article/48594.htm JS原型与原型链终极详解_proto_.prototype及const ...

随机推荐

  1. Oracle中的rownum,ROWID的 用法

    1.ROWNUM的使用——TOP-N分析 使用SELECT语句返回的结果集,若希望按特定条件查询前N条记录,可以使用伪列ROWNUM. ROWNUM是对结果集加的一个伪列,即先查到结果集之后再加上去的 ...

  2. mac下安装配置nginx环境

    本文介绍 nginx 在mac上的安装. 我是通过brewhome 来安装的. brew install nginx 一路顺畅. 下面是安装信息. 复制代码 代码如下: hematoMacBook-P ...

  3. ACM Sdut 2158 Hello World!(数学题,排序) (山东省ACM第一届省赛C题)

    题目描述 We know thatIvan gives Saya three problems to solve (Problem F), and this is the firstproblem. ...

  4. 练习SignalR使用

    前言 随着Ajax越来越普遍的使用,前端页面跟后台服务也越来越密切的进行交互,实现前后端进行实时的消息传递尤为重要,一文件上传为例,现在普遍使用ajax上传然后通过flash进行文件进度的显示,这是目 ...

  5. 第一天的CI笔记

    1 CI不区分大小写2. http://xxx.com/index/[控制器名称]/[控制器里面方法的确名称]/[传入方法的参数 ]/ 3. 控制器及控制器类名称与文件名称一致, 继承 CI_Cont ...

  6. python细节

    1.assert 断言语句,可判断一句话真假,若为假会抛出AssertionError. eg. assert 1==1     assert 1==2则AssertionError 2.单引号双引号 ...

  7. javascript图片预先加载

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  8. jquery 效果

    效果1.基本效果    1.1 show([speed,[easing],[fn]]) 如果元素本身是可见的,则不对其作任何改变.如果元素是隐藏的,则使其可见.        $("p&qu ...

  9. 利用def生成dll文件

    DLL中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport),这里不再举例说明:另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被 ...

  10. sizeof()用法

    参考:sizeof_百度百科 sizeof()用法汇总(经典) 声明:本文是笔者抽出对自己有用的细节,对前两文的总结. 1.sizeof概念 sizeof是C语言中判断数据类型或者表达式长度符:不是一 ...