正确理解javascript的this关键字

标签: JavaScript javascript 作用域 面向对象 | 发表时间:2011-10-25 08:55 | 作者:三水清 BeerBubble
出处:http://js8.in


javascript有this关键字,this跟javascript的执行上下文密切相关,很多前端开发工程师至今对this关键字还是模棱两可,本文将结合代码讲解下javascript的this关键字

this和对象的关系

首先来看下面的代码:

var person = {
	name:'Theo Wong',
	gender:'male',
	getName:function(){
		console.log(person.name);
	}
};
person.getName();

定义了一个person对象,对象中包含了name、gender属性,还包括了一个getName的方法,其作用是输出person对象的name。在这种情况下,我们可以使用this来在person对象中代替person对象本身,所以上面的代码跟下面的直接结果是一样的:

var person = {
	name:'Theo Wong',
	gender:'male',
	getName:function(){
		console.log(this.name);
	}
};
person.getName();

请记住一点:this永远指向的是函数对象的所有者!上面的例子中getName的所有者是person对象,所以this指代的是person。

this和全局对象

我们再来看看再全局对象中,this指代的是什么,我们知道javascript是脚本语言,所以javascript的执行需要有一个宿主环境,在浏览器中这个宿主环境就是window对象,所以在全局函数中,this指代的是window对象(除非使用new,call,apply方法来改变this的指代关系)。懂得了这个关键点,下面的代码就好理解了:

var a = 1;
console.log(a);//1
console.log(this.a);//1
console.log(window.a);//1

很多前端开发工程师经常使用在函数名字之前添加个window来调用函数,这是因为在浏览器中全局对象就是window,所有的函数变量都是在window对象之中,所以下面的代码中的this指代window对象就好理解了:

var a = 1;
function foo(){
	var b = 2;
	console.log(this.a+b);//3
}
foo();

所以说,只要记住:this永远指向的是函数对象的所有者,即this的值是由激活执行上下文代码的调用者决定的,就好理解this的指代关系了。

函数构造器中的this

当函数作为构造器使用new关键字实例化时,this的指代关系又是怎样的呢?看下面的代码:

var Person = function(){
	this.name = 'Theo Wong';
}
var person = new Person();
console.log(person.name);

new执行过程会首先执行Person的构造器[[construct]],然后在调用[[call]]方法给this赋值,这个执行过程可以简单理解为三步

  1. 首先建立一个空的对象object,类似var obj={}
  2. 然后将空对象使用Person的call操作,类似Person.call(obj)
  3. 执行完Person之后再return this,完成new过程,赋值给person变量

所以经过new加工过的函数,this的函数调用者是Person本身,而不是window了。

嵌套函数中的this

在嵌套函数中,this的指代关系有会是怎样的呢?看下面的代码:

var myObject = {
  func1:function() {
     console.log(this); //myObject
     var func2=function() {
        console.log(this); //window
        var func3=function() {
           console.log(this); //window
        }();
     }();
  }
}; 
myObject.func1();

在嵌套函数中,由于嵌套函数的执行上下文是window,所以this指代的是window对象,其实这是ECMA-262-3的一个bug,在最新的ECMA-262-5中已经修复。

事件处理中的this

在javascript中处理事件函数中,this的指代关系就更加扑朔离迷了。我们建立一个showValue函数,函数内容如下:

var showValue = function(){
	console.log(this.value);
};

现在有个input,我们给input元素添加click事件,当点击input时触发showValue函数,看看现在的this指代的是什么对象。

<input id="test" type="text" />

通过dom.onclick绑定事件

document.getElementById('test').onclick = showValue;

运行代码会得到预期的结果,showValue虽然定义在全局对象中,但是当采用了onclick的绑定方式时,showValue是作为dom的onclick方法被调用的,所以它的this应该指代的是dom对象,而不再是window对象。

写在html标签内

<input id="test" type="text" onclick="showValue();" />

当点击dom时,我们获取不到正确的this,这是为什么呢?

此时的this指代的是window对象,因为window对象中没有定义value的值,所以获取不到this.value。其实此时的不是将showValue函数赋值给dom对象的onclick,而是引用!所以上面的代码跟下面的代码关系是一样的:

document.getElementById('test').onclick = function(){
    showValue();
};

根据上面说的javascript嵌套函数的this值,我们可以得出现在showValue的this其实是window。

通过addEventListener/attachEvent绑定事件监听

<input type="text" id="test" />
<script type="text/javascript">
var dom = document.getElementById('test');
id = 'window';
function test(){
	alert(this.id);
}
dom.addEventListener?dom.addEventListener('click',test,false):dom.attachEvent('onclick',test);
//addEventListener test
//attachEvent window
</script>

这种绑定事件监听的方式,attachEvent this是window对象,而addEventListener则是dom对象的。@魔堕轮回 提出来的bug~嘎嘎

使用call和apply方法改变this

在Function对象原型(Function.prototype)中有两个方法:call和apply,通过call和apply可以改变this的值, 它们都接受第一个参数作为调用执行上下文中this的值。它们的不同点就是apply第二个参数为数组,call接收的参数是依次传入的。

var obj = {
	name:'Theo Wong',
	desc:'一个前端开发者'
};
var getInfo = function(){
	console.log(this.name+this.desc);
};
getInfo.call(obj);
//Theo Wong一个前端开发者

总结

this是javascript的重要关键字,理解掌握this关键字在不同的执行上下文指代关系,才能避免代码犯一些不必要的错误。深入了解javascript的代码执行过程,及其执行上下文,推荐阅读《javascript的词法作用域

声明:文章未声明为原创文章,本文链接 http://js8.in/851.html. 转载请注明转自 JS8.IN ™

随机文章


© 三水清 for 三水清, 2011. | 2 comments |在微博关注我:@清-三水清
收藏到: 人人网 | 豆瓣 | 开心网 | QQ书签 | 新浪微博 | 腾讯微博
Post tags: , ,

相关 [正确 理解 javascript] 推荐:

正确理解javascript的this关键字

- BeerBubble - 三水清
javascript有this关键字,this跟javascript的执行上下文密切相关,很多前端开发工程师至今对this关键字还是模棱两可,本文将结合代码讲解下javascript的this关键字. 定义了一个person对象,对象中包含了name、gender属性,还包括了一个getName的方法,其作用是输出person对象的name.

正确理解ThreadLocal

- - Java - 编程语言 - ITeye博客
转自: http://www.iteye.com/topic/103804. 首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的. 另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本.

我对Javascript闭包的一点点理解

- dZYflE9Uh7sPhuMdcCh6XjSnpJxRHzciSsHWoGK7lWFGNvoc - ITeye博客
如果前端人员不懂Javascript闭包,那只能说他压根就没懂Javascript,只能算入门级. 本篇主要是写本人对闭包的一些理解,欢迎拍板. A "closure " is an expression (typically a function) that can have free varuables together with an environment that binds those variables (that "closes" the expression).

高性能JavaScript模板引擎原理解析

- - 腾讯CDC
  随着 web 发展,前端应用变得越来越复杂,基于后端的 javascript(Node.js) 也开始崭露头角,此时 javascript 被寄予了更大的期望,与此同时 javascript MVC 思想也开始流行起来. javascript 模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注,近一年来在开源社区中更是百花齐放,在 Twitter、淘宝网、新浪浪微博、腾讯QQ空间、腾讯微博等大型网站中均能看到它们的身影.

(转)全面理解面向对象的 JavaScript

- - JavaScript - Web前端 - ITeye博客
要掌握好 JavaScript,首先一点是必须摒弃一些其他高级语言如 Java、C# 等类式面向对象思维的干扰,全面地从函数式语言的角度理解 JavaScript 原型式面向对象的特点. 当今 JavaScript 大行其道,各种应用对其依赖日深. web 程序员已逐渐习惯使用各种优秀的 JavaScript 框架快速开发 Web 应用,从而忽略了对原生 JavaScript 的学习和深入理解.

理解JavaScript的单线程运行机制及setTimeout(fn,0)

- - JavaScript - Web前端 - ITeye博客
阮老师的链接: http://javascript.ruanyifeng.com/bom/timer.html. 一、为什么JavaScript是单线程. JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事. 那么,为什么JavaScript不能有多个线程呢. JavaScript的单线程,与它的用途有关.

高性能JavaScript模板引擎原理解析

- - 极客521 | 极客521
随着 web 发展,前端应用变得越来越复杂,基于后端的 javascript(Node.js) 也开始崭露头角,此时 javascript 被寄予了更大的期望,与此同时 javascript MVC 思想也开始流行起来. javascript 模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注,近一年来在开源社区中更是百花齐放,在 Twitter、淘宝网、新浪微博、腾讯QQ空间、腾讯微博等大型网站中均能看到它们的身影.

用最通俗易懂的代码帮助新手理解javascript闭包

- - 博客园_首页
我同样也是个javascript新手,怎么说呢,先学的jquery,精通之后发现了javascript的重要性,再回过头来学javascript面向对象编程. 最近看了几篇有关javascript闭包的文章,包括最近正火的 汤姆大叔系列,还有《javascript高级程序设计》中的文章,……我看不懂,里面有些代码是在大学教科书中看都没看过的,天书一般.

谈正确理解 CAP 理论[转自网络]

- - 互联网 - ITeye博客
转载自:http://www.douban.com/group/topic/11765014/. CAP 理论在搞分布式的程序员中已经是路人皆知了. 但是 CAP 理论就好比是相对论,虽然所有的人都知道,但是却没有多少人真正理解. 要真正理解 CAP 理论必须要读懂它的形式化描述. 形式化描述中最重要的莫过于对 Consistency, Availability, Partition-tolerance 的准确定义.