JavaScript中的this总是让人迷惑,应该是js众所周知的坑之一。 个人也觉得js中的this不是一个好的设计,由于this晚绑定的特性,它可以是全局对象,当前对象,或者…有人甚至因为坑大而不用this。

其实如果完全掌握了this的工作原理,自然就不会走进这些坑。来看下以下这些情况中的this分别会指向什么:

1.全局代码中的this

  1. alert(this)//window

全局范围内的this将会指向全局对象,在浏览器中即使window。

2.作为单纯的函数调用

  1. function fooCoder(x) {
  2. this.x = x;
  3. }
  4. fooCoder();
  5. alert(x);// 全局变量x值为2
这里this指向了全局对象,即window。在严格模式中,则是undefined。
 
3.作为对象的方法调用
  1. var name = "clever coder";
  2. var person = {
  3. name : "foocoder",
  4. hello : function(sth){
  5. console.log(this.name + " says " + sth);
  6. }
  7. }
  8. person.hello("hello world");

输出 foocoder says hello world。this指向person对象,即当前对象。

4.作为构造函数

  1. new FooCoder();

函数内部的this指向新创建的对象。

5.内部函数

  1. var name = "clever coder";
  2. var person = {
  3. name : "foocoder",
  4. hello : function(sth){
  5. var sayhello = function(sth) {
  6. console.log(this.name + " says " + sth);
  7. };
  8. sayhello(sth);
  9. }
  10. }
  11. person.hello("hello world");//clever coder says hello world

在内部函数中,this没有按预想的绑定到外层函数对象上,而是绑定到了全局对象。这里普遍被认为是JavaScript语言的设计错误,因为没有人想让内部函数中的this指向全局对象。一般的处理方式是将this作为变量保存下来,一般约定为that或者self:

  1. var name = "clever coder";
  2. var person = {
  3. name : "foocoder",
  4. hello : function(sth){
  5. var that = this;
  6. var sayhello = function(sth) {
  7. console.log(that.name + " says " + sth);
  8. };
  9. sayhello(sth);
  10. }
  11. }
  12. person.hello("hello world");//foocoder says hello world

6.使用call和apply设置this

  1. person.hello.call(person, "world");

apply和call类似,只是后面的参数是通过一个数组传入,而不是分开传入。两者的方法定义:

  1. call( thisArg [,arg1arg2,… ] ); // 参数列表,arg1,arg2,...
  2. apply(thisArg [,argArray] ); // 参数数组,argArray

两者都是将某个函数绑定到某个具体对象上使用,自然此时的this会被显式的设置为第一个参数。

简单地总结

  简单地总结以上几点,可以发现,其实只有第六点是让人疑惑的。

  其实就可以总结为以下几点:

  1.当函数作为对象的方法调用时,this指向该对象。

  2.当函数作为淡出函数调用时,this指向全局对象(严格模式时,为undefined)

  3.构造函数中的this指向新创建的对象

  4.嵌套函数中的this不会继承上层函数的this,如果需要,可以用一个变量保存上层函数的this。

  再总结的简单点,如果在函数中使用了this,只有在该函数直接被某对象调用时,该this才指向该对象。

  1. obj.foocoder();
  2. foocoder.call(obj, ...);
  3. foocoder.apply(obj, …);

更进一步

  我们可能经常会写这样的代码:

  1. $("#some-ele").click = obj.handler;

如果在handler中用了this,this会绑定在obj上么?显然不是,赋值以后,函数是在回调中执行的,this会绑定到$(“#some-div”)元素上。这就需要理解函数的执行环境。本文不打算长篇赘述函数的执行环境,可以参考《JavaScript高级程序设计》中对执行环境和作用域链的相关介绍。这里要指出的时,理解js函数的执行环境,会更好地理解this。

  那我们如何能解决回调函数绑定的问题?ES5中引入了一个新的方法,bind():

  1. fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
当绑定函数被调用时,该参数会作为原函数运行时的this指向.当使用new 操作符调用绑定函数时,该参数无效.
arg1, arg2, ...
当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数.
 

该方法创建一个新函数,称为绑定函数,绑定函数会以创建它时传入bind方法的第一个参数作为this,传入bind方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.

  显然bind方法可以很好地解决上述问题。

  1. $("#some-ele").click(person.hello.bind(person));
  2. //相应元素被点击时,输出foocoder says hello world

其实该方法也很容易模拟,我们看下Prototype.js中bind方法的源码:

  1. Function.prototype.bind = function(){
  2. var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  3. return function(){
  4. return fn.apply(object,
  5. args.concat(Array.prototype.slice.call(arguments)));
  6. };
  7. };

明白了么?

  相信看完全文以后,this不再是坑~

原文地址:http://www.admin10000.com/document/2003.html

(转)javascript中的this的更多相关文章

  1. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  2. javascript中的this与函数讲解

    前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码, ...

  3. JavaScript 中的数据类型

    Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...

  4. javascript中的操作符详解1

    好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...

  5. 掌握javascript中的最基础数据结构-----数组

    这是一篇<数据结构与算法javascript描述>的读书笔记.主要梳理了关于数组的知识.部分内容及源码来自原作. 书中第一章介绍了如何配置javascript运行环境:javascript ...

  6. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  7. 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型

    前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...

  8. 简单分析JavaScript中的面向对象

    初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...

  9. Javascript中的valueOf与toString

    基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...

  10. 关于javascript中的this关键字

    this是非常强大的一个关键字,但是如果你不了解它,可能很难正确的使用它. 下面我解释一下如果在事件处理中使用this. 首先我们讨论一下下面这个函数中的this关联到什么. function doS ...

随机推荐

  1. MySQL 5.6 root密码丢失

     windows下mysql密码忘记了 第一步:netstat -nat(可以查看mysql是否启动了,如果启动了,可以用输入net stop mysql(或者通过任务管理器结束进程)) 第二步:my ...

  2. [置顶] Objective-C,/,ios,/iphone开发基础:分类(category,又称类别)

    在c++中我们可以多继承来实现代码复用和封装使程序更加简练.在objective-c中只能单继承,不能多继承,那么除了协议protocol之外,我们可以实现类似多继承的一个方法就是,分类(catego ...

  3. 17.1.1.5 Creating a Data Snapshot Using mysqldump

    一种方式创建一个数据库的快照在一个存在的master 数据库是使用mysqldump 来创建你需要复制的所有数据库的dump. 一旦数据dump 是完成,你然后倒入数据到slave 在开始复制过程前 ...

  4. jni.h头文件详解一

    1.jni.h头文件路径: /usr/lib/jvm/jdk_1.6.0_43/include/jni.h 2.jni.h头文件组成分析图: 3.下面通过上图进行分析讲解jni.h头文件. 一. jn ...

  5. 检查string是否为double

    之前写的方法,使用try catch来处理 如果能捕获异常就说明问题 public bool CheckLegal() { double number; bool flag = true; try { ...

  6. Java中Map遍历的四种方案

    在Java中如何遍历Map对象 方式一 这是最常见的并且在大多数情况下也是最可取的遍历方式.在键值都需要时使用. Map<Integer, Integer> map = new HashM ...

  7. Poj 1151-Atlantis 矩形切割

    题目:http://poj.org/problem?id=1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissio ...

  8. 采集爬虫中,解决网站限制IP的问题? - wendi_0506的专栏 - 博客频道 - CSDN.NET

    采集爬虫中,解决网站限制IP的问题? - wendi_0506的专栏 - 博客频道 - CSDN.NET undefined

  9. .Net设计模式_适配器模式

    引言: 有一次我看到一个朋友拿出一个三角型的东西,好奇的上去一看你,我勒个去,传说中的万能插口转接器(插口适配器). 一面是插入口,集合了我认识的所有插口的形状,也有国内没看见过的:另一个是跟插座接触 ...

  10. String类、 StringBuffer、基本数据类型对象包装类

    一.概述 Sting s1 = "abc";    //s1是一个类类型变量,"abc"是一个对象. String s2 = new String(" ...