个人理解+google翻译。如有错误,请留言指正。原文来自MDN: this

简介

Javascript中一个函数的this关键字的行为相对其它语言有些不同。在严格模式和非严格模式间也有区别。

在大多数情况下,this的值由函数如何调用来决定。this值不能在函数执行过程中赋值设置,并且每次函数调用时this值可能也不相同。ES5通过添加bind方法设置函数的this值,无论函数如何被调用。(this值永久不变)

全局上下文中

全局执行环境中(函数外部),无论在与不在严格模式下this指向全局对象。

console.log(this.document === document); //true
//在web浏览器中,window对象即是全局对象:
console.log(this === window); // true
this.a=37;
console.logn(window.a); //

function上下文

在函数内部,this值依赖于函数如何调用。

简单调用

function f2(){
"use strict";//使用严格模式
return this;
}
f2() === undefined;

在上面的例子中,this值没有在函数调用的时候被设置。由于代码没有在严格模式下,this值肯定总会是默认为全局对象。

function f2(){
"use strict";//使用严格模式
return this;
}
f2() === undefined;

严格模式下,this值保持在进入执行环境时设置的值。如果this值未定义,则为undefined;this值也能被设置为任意值:如null、42或"I am not this";

注意:在第二例子中,this值应为undefined,因为f2函数被调用时没有提供任何引用[原文:base],(例如:window.f2())。这一特性在某些浏览器初始支持严格模式时没有实现,造成返回错误的对象:window

function作为对象方法

当函数作为对象方法调用时,该函数的this值设为调用该方法的对象。

在下例中,当o.f()被调用,函数内部this绑定为o对象(inside the function this is bound to the o object).

var o={
prop:37;
f:function(){
return this.prop;
}
};
console.log(o.f());//

注意:this的这种特性不受其函数如何定义或函数的定义位置的影响。在上例,我们把函数定义为对象o的内部成员f。然而我们也可以轻易的先定义这个函数,后面再把它附加到o.f上,结果是一样的。

var o ={prop:37};
function independent{
return this.prop;
}
o.f=independent;
console.log(o.f());//

这段代码表明:函数的调用来自对象o的f方法;同样,this的绑定只受最近参考成员的影响。在下面的例子里,调用该函数的时候,则为对象o.b的g方法。此次函数执行时,函数内的this指向o.b.事实上,与o.b对象是o对象的成员没有任何关系,最近参考才是重要的。

var o ={prop:37};
function independent{
return this.prop;
}
o.f=independent;
o.b{prop:42,g:independent};
console.log(o.f());//
console.log(o.b.g());//

function在原型链上

同样的概念也适用于在原型链上某些地方定义方法。如果该方法定义在对象的原型链上,this指向调用该方法的对象。【假设该方法是对象的成员】

var o = {f:function(){return this.a + this.b}};
var p = Object.create(o);
p.a=1;
p.b=4;
console.log(p.f());//

在上面的例子中,对象o分配给变量p,p没有自己的属性f,p从其原型中继承f属性。原型中f属性的查找最终会在对象o上以一个成员的身份找到;查找开始以p.f为参考,所以函数内的this取值为对象p。由于f作为p的方法被调用,this指向p,这Javascript原型继承一个有意思的特性。

个人添加了一个Object.create()例子,方便自我解惑:详情请参考MDN:Object.create()

o = Object.create(Object.prototype, {//对象内属性对应于Object.defineProperties的第二个参数
// foo is a regular "value property" --foo是一个普通值属性
foo: { writable:true, configurable:true, value: "hello" },
// bar is a getter-and-setter (accessor) property --bar是一个getter、setter存取属性
bar: {
configurable:false,//默认:false,属性的类型能被修改或该属性可以被删除时为true
enumerable:false,//默认:false,对象属性枚举属性时显示该属性为true
//writable:false, //默认:false,当属性值能通过赋值操作而改变时为true
//value:"hi",//与属性相关联的值。可以是任何有效的JavaScript值(数字,对象,函数等)。
get: function() { return this.value || 10 },//以一个函数作为getter方法的属性,如果没有指定函数则为undined。返回其属性值
set: function(value) {this.value=value}//以一个函数作为setter方法的属性,如果没有指定函数则为undined。接收新的参数值成为属性值
}
});
console.log(o.bar);//
o.bar="hi";
console.log(o.bar); //hi

bar定义中有两行注释,如果取消注释符号,在Firefox下会报错:不允许在指定get 或 set时 指定其value属性或为定义writable属性。[writable为true或false都会报错]

function作为(Object.defineProperty中的)getter方法或setter方法

同样的概念再次适用于函数作为getter方法或setter方法。函数用作getter或setter方法则其this绑定到已经设置set或set属性的所属对象。(原文: A function used as getter or setter has its this bound to the object from which the property is being set or gotten.)

function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var o ={
re : 1,
im : -1,
get phase(){//ES5的写法,还是建议用__defineGetter__这种API比较好,ie7 8 不支持
return Math.atan2(this.im,this.re);
},
set txt(value){
this.re=value.re;
this.im=value.im;
}
};
Object.defineProperty(o,'modulus1',{get : modulus,enumerable : true,configurable : true});//ie7 不支持此方法 ie8 不支持get:
console.log(o.phase,o.modulus1);// -0.78 1.414
o.txt={re:12,im:3};//o.txt({re:12,im:3});报错:o.txt is not a function
console.log(o.phase,o.modulus1);//0.24 12.36

ES5 的getter、setter方法在ie7 8上不支持,汗的没汗了……

function作为构造函数

当函数通过new关键字做为构造函数时,函数的this指向该构造函数实例化后的对象。

注意:构造函数默认返回的对象被this引用,构造函数也可以返回其它对象。如果返回值不是一个对象,那么返回默认this引用的对象。( 原文:while the default for a constructor is to return the object referenced by this, it can instead return some other object (if the return value  isn't an object, then the this object is returned))

/*
* Constructors work like this:构造函数以类似下面的方式运行:
*
* function MyConstructor(){
* // Actual function body code goes here. Create properties on |this| as
* // desired by assigning to them. E.g.,
* // 译:实际的代码放在这里,通过 this 创建需要的属性及赋值。如:
* this.fum = "nom";
* // et cetera...译:其它代码
* // If the function has a return statement that returns an object, that
* // object will be the result of the |new| expression. Otherwise, the
* // result of the expression is the object currently bound to |this|
* // (i.e., the common case most usually seen).
* //如果构造函数通过return语句返回一个对象,这个对象将会通过new表达式返回的实际对象。
* //如果函数体内没有return语句,则通过new表达式返回的对象为当前this默认引用的对象(这也是我们一般常见的情况)
* }
*/
function c(){
this.a=37;
}
var o = new c();
console.log(o.a);//
function c2(){
this.a = 37;
return {a:38};
}
o = new c2();
console.log(o.a);//

在c2函数中,因为在构造函数运行并返回了一个对象,this默认绑定的对象则被简单的丢弃。(实际上是使语句this.a = 37;成为废弃代码。也没有完全被废弃,因为它得到运行,只是在没有外部影响的情况下而被排除。)

通过call或apply方法调用

函数内使用this关键字,通过call或apply方法调用该函数时,this值被指定为一个特定的对象,全部function继承于Function.prototype(all functions inherit from Function.prototype)

function add(c,d){
return this.a + this.b + c + d;
}
var o ={a:1,b:3};
//第一个参数是一个对象作为this,随后的参数作为函数调用参数
add.call(o,5,7); //1+3+5+7 = 16
//第一个参数是一个对象作为this,第二个参数是一个数组,该数组成员做函数调用参数
add.apply(o,[10,20]);//1+3+10+20 = 34

ES5 bind 方法

ES5 添加Function.prototype.bind。调用f.bind(someObject)创建与f具有相同内容和作用域的新函数,但原来的函数中的this在新函数中永久指向bind方法第一个参数,不管该函数如何调用。

function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); //azerty
var o ={a:37,f:f,g:g};
console.log(o.f(),o.g()); // 37,azerty

作为DOM事件处理函数

当function作为事件处理函数,this指向触发该事件的DOM元素。(有些浏览器不支持下面通过addEventListener方法为监听动态添加方法,如:IE)。

//作为监听器时 改变相关元素为蓝色
function bluify(e){
console.log(this === e.currentTarget); //一直为true
console.log(e.currentTarget);
console.log(this === e.target); //当currentTarge和target为同一对象时为true
console.log(e.target);
this.style.backgroundColor="#A5D9F3";
//e.stopPropagation(); //阻止事件冒泡
}
//获取document下元素列表
var elements = document.body.getElementsByTagName('*');
//添加bluify方法作为点击事件监听器,使元素被点击后变为蓝色
for(var i = 0;i < elements.length; i++){
elements[i].addEventListener('click',bluify,false);
}

上面的代码在某个结构层叠在3层或以上的页面下的控制台中(firebug/google chrome console)运行一下,会表现出一种怪异现象,无论点哪个元素,整个页的背景全部变为蓝色。试着把代码e.stopPropagation()的注释取消掉,或审查下元素,就应该知道为什么了。还不懂?请搜索 javascript 事件冒泡 相关资料。

在内联事件处理中

当代码在内联处理器中执行时,代码中的this被设为其上有事件监听的DOM元素:

<button onclick="alert(this.tagName.toLowerCase());">Show this</button>

上面的警告弹出框显示button。 Note however that only the outer code has its this set this way:【实在翻译不出来了,将就的这么翻译吧:但是要注意,这种方式只有函数外面的代码中的this值才会被设置为事件监听DOM元素】

<button onclick="alert((function(){return this}()));">Show inner this</button>

这种情况下,函数内部的this没有被指定,所以该函数返回全局对象或window对象。(即非严格模式下调用代码中的this没有被指定时的默认对象)。

function's this总结(自加)

  • 指向全局对象
  1. 函数体外部,script标签内直接调用this
  2. 简单调用函数(非严格模式下)
  • 指向对象
  1. 函数作为对象方法(无论函数是否在对象内定义),this指向调用该方法的最近参考对象
  2. 函数在对象的原型链上
  3. 函数作ES5下对象的getter或setter方法
  • 指向实例化对象或普通(hash)对象
  1. 函数作为构造函数或构造函数内返回一个普通对象
  • 指向特定对象
  1. 函数被call或apply调用。如:fun.call(obj,param),fun.apply(obj,[param1,param2])
  • 永久指向一个对象(ES5)
  1. 函数通过bind方法永久指向一个对象,无论该函数如何调用
  • 指向事件触发DOM元素
  1. 函数作为事件处理器(动态添加)
  2. 在内联事件处理器代码中(如果有function(){},则为function的代码外部)的this,如<button onclick="alert(this.tagName.toLowerCase());functiong(){//代码}"></button>

PS:用脑子里的半吊子英语水平+google翻译+有道翻译 这三种工具耗时3天按个人理解翻译出这篇文章。总算体会到了IT英语翻译的苦闷之处,不过自己也算有了翻译的经验,小自豪一把。如有错误,请列位拍砖指正。谢谢!

译文:javascript function中的this的更多相关文章

  1. Javascript Function()中的降龙十八掌

    原文地址:http://tutorialzine.com/2014/08/what-does-this-function-do/ 下面列出十八个JS function,看你知道这些函数是干嘛用的,你能 ...

  2. JavaScript jQuery 中定义数组与操作及jquery数组操作

    首先给大家介绍javascript jquery中定义数组与操作的相关知识,具体内容如下所示: 1.认识数组 数组就是某类数据的集合,数据类型可以是整型.字符串.甚至是对象Javascript不支持多 ...

  3. javascript函数中变量重名

    <script type="text/javascript"> function fun(a){ console.log(a); // function var a=1 ...

  4. 关于<a href='javascript:function()'>

    <a href='javascript:function()'> 这样写是为了让这个链接不要链接到新页面转而执行一段js代码.和onclick能起到同样的效果,一般来说,如果要调用脚本还是 ...

  5. JavaScript ES7 中使用 async/await 解决回调函数嵌套问题

    原文链接:http://aisk.me/using-async-await-to-avoid-callback-hell/ JavaScript 中最蛋疼的事情莫过于回调函数嵌套问题.以往在浏览器中, ...

  6. [记录] javascript 对象中使用setTimeout

    参考:Javascript对象中关于setTimeout和setInterval的this介绍 使用最后一个方法终于弄好了,简直了,在对象中使用setTimeout原来是这样的 做的是分钟倒计时,倒数 ...

  7. JavaScript function函数种类(转)

    转自:http://www.cnblogs.com/polk6/p/3284839.html JavaScript function函数种类 本篇主要介绍普通函数.匿名函数.闭包函数 目录 1. 普通 ...

  8. JavaScript function函数种类介绍

    JavaScript function函数种类介绍 本篇主要介绍普通函数.匿名函数.闭包函数 1.普通函数介绍 1.1 示例 ? 1 2 3 function ShowName(name) {     ...

  9. 第一百节,JavaScript表达式中的运算符

    JavaScript表达式中的运算符 学习要点: 1.什么是表达式 2.一元运算符 3.算术运算符 4.关系运算符 5.逻辑运算符 6.*位运算符 7.赋值运算符 8.其他运算符 9.运算符优先级 E ...

随机推荐

  1. MyEclipse安装插件的几种方法 转

    http://www.cnblogs.com/pharen/archive/2012/02/08/2343342.html MyEclipse安装插件的几种方法 本文讲解MyEclipse(MyEcl ...

  2. 文件尾存在EOF吗?

    参考:http://bbs.csdn.net/topics/290027166 我們先一起來看看FILE是怎么定義的:   FILE                          <STDI ...

  3. Mac 下配置Tomcat7和eclipse中配置tomcat

    转载自: http://www.cnblogs.com/weilaikeji/archive/2013/05/29/3106473.html 1.下载Tomcat 从Tomcat项目主页下载相关压缩包 ...

  4. 那些著名或非著名的iOS面试题-前编

    1.如何追踪app崩溃率,如何解决线上闪退 当iOS设备上的App应用闪退时,操作系统会生成一个crash日志,保存在设备上.crash日志上有很多有用的信息,比如每个正在执行线程的完整堆栈跟踪信息和 ...

  5. 想学React Native?你只需要一个App!(11月5号更新)

    最近有点空闲时间,顺手研究下react-native,2013年的时候在老师的指导下使用jQuery Mobile做过手机应用,那个运行速度慢呀!让我对WebApp和PhoneGap这一类的跨平台Ap ...

  6. hdu 4612 边连通度缩点+树的最长路径

    思路:将以桥为分界的所有连通分支进行缩点,得到一颗树,求出树的直径.再用树上的点减去直径,再减一 #pragma comment(linker, "/STACK:1024000000,102 ...

  7. C语言下的简易计算器

    #include <stdio.h> #include <math.h> int main() { double data1, data2; char op; == scanf ...

  8. js如何判断一个数组中是否有重复的值

    引自:http://bbs.tianya.cn/post-414-38497-1.shtml 方法一: var ary = new Array("111","22&quo ...

  9. div a 和 div > a 的区别———后者指作用到div下一级的 a 标签 ,仅一级

    div a 和 div > a 的区别---后者指作用到div下一级的 a 标签 ,仅一级 如: <div> <a href="#">可以作用到< ...

  10. JS中的原型继承和多重继承

    概念:1原型继承是创建新类型对象----子类型,子类型基于父类型,子类型拥有父类型所有的属性和方法(从父类型继承得到),然后修改其中的部分内容或者添加新的内容.继承最好在子类型模型可以被视为父类型对象 ...