JavaScript的this关键字的理解

概念性的概述this

当一个函数创建后,一个关键字this就随之(在后台)创建,它链接到一个对象,而函数正是在这个对象中进行操作。换句话说,关键字this可在函数中使用,是对一个对象的引用,而函数正是该对象的属性或方法。

让我们来看这个对象:

<!DOCTYPE html><html lang="en"><body><script>
var cody = {
living:true,
age:23,
gender:'male',
getGender:function(){return cody.gender;}
};
console.log(cody.getGender()); // logs 'male'
</script></body></html>

注意在函数getGender里,由于在cody对象内部,我们可以通过.来获取gender属性(也就是cody.gender)。也可以用this来获取cody对象,因为this正是指向cody对象。

<!DOCTYPE html><html lang="en"><body><script>
var cody = {
living:true,
age:23,
gender:'male',
getGender:function(){return this.gender;}
};
console.log(cody.getGender()); // logs 'male'
</script></body></html>

this.gender中this指向cody对象,而getGender函数可以操作cody对象。

关于this的主题可能有点让人感到困惑,其实不必如此。仅记住,通常,this指向的对象正是包含函数的对象,而不是函数本身(当然也有例外,例如采用关键字new或者call()和apply())。

重要提示

- 关键字this就像其他的变量,唯一不同就是你不能更改它。

- 不同于传给函数的其他参数和变量,在调用函数的对象中,this是一个关键字(而不是属性)。

如何确定this的值?

this传递给所有的函数,它的值取决于函数运行时何时被调用。这里请注意,因为这是你需要记住的一个很特别的地方。

下面的代码中myObject对象有个属性sayFoo,它指向函数sayFoo。当在全局域中调用sayFoo函数时,this指向window对象。当myObject调用函数时,this指向的是myObject。

因为myObject有个叫foo的属性,在这里被使用。

<!DOCTYPE html><html lang="en"><body><script>
var foo = 'foo';
var myObject = {foo: 'I am myObject.foo'};
var sayFoo = function() {
console.log(this['foo']);
};
// give myObject a sayFoo property and have it point to sayFoo function
myObject.sayFoo = sayFoo;
myObject.sayFoo(); // logs 'I am myObject.foo' 12
sayFoo(); // logs 'foo'
</script></body></html>

很清楚,this的值取决于函数什么时候被调用。myObject.sayFoo和sayFoo都指向同样的函数,但sayFoo()调用的上下文不同,this的值也就不同。下面是类似的代码,head对象(window)显式使用,希望对你有用。

<!DOCTYPE html><html lang="en"><body><script>
window.foo = 'foo';
window.myObject = {foo: 'I am myObject.foo'};
window.sayFoo = function() { ! console.log(this.foo); };
window.myObject.sayFoo = window.sayFoo;
window.myObject.sayFoo();
window.sayFoo();
</script></body></html>

确保当你有多个引用指向同一个函数的时候,你清楚的知道this的值是随调用函数的上下文的不同而改变。

重要提示

- 除了this以外的所有变量和参数都属于静态变量范围(lexical scope)。

在嵌入函数内this指向head对象

你可能想知道在嵌入在另外一个函数的函数中使用this会发生什么事。不幸的是在ECMA 3中,this不遵循规律,它不指向函数属于的对象,而是指向head对象(浏览器的window对象)。

在下面的代码,func2和func3中的this不再指向myObject,而是head对象。

<!DOCTYPE html><html lang="en"><body><script>
var myObject = {
func1:function() {
console.log(this); //logs myObject
varfunc2=function() {
console.log(this); //logs window, and will do so from this point on
varfunc3=function() {
console.log(this); //logs window, as it's the head object
}();
}();
}
};
myObject.func1();
</script></body></html>

然而在ECMAScript 5中,这个问题将会得到修正。现在,你应该意识到这个问题,尤其是当你将一个函数的值传递到另一个函数时。

看看下面的代码,将一个匿名函数传给foo.func1,当在foo.func1中调用匿名函数(函数嵌套在另一个函数中),匿名函数中this将会指向是head对象。

<!DOCTYPE html><html lang="en"><body><script>
var foo = {
func1:function(bar){
bar(); //logs window, not foo
console.log(this);//the this keyword here will be a reference to foo object
}
};
foo.func1(function(){console.log(this)});
</script></body></html>

现在你不会忘了,如果包含this的函数在另一个函数中,或者被另一个函数调用,this的值将会指向的是head对象(再说一次,这将在ECMAScript 5中被修正。)

解决嵌套函数的问题

为了使this的值不丢失,你可以在父函数中使用一个作用域链(scope chain)来保存对this进行引用。下面的代码中,使用一个叫that的变量,利用它的作用域,我们可以更好的保存函数上下文。

<!DOCTYPE html><html lang="en"><body><script>
var myObject = {
myProperty:'Icanseethelight',
myMethod:function() {
var that=this; //store a reference to this (i.e.myObject) in myMethod scope varhelperFunctionfunction(){//childfunction
var helperFunction function() { //childfunction
//logs 'I can see the light' via scope chain because that=this
console.log(that.myProperty); //logs 'I can see the light'
console.log(this); // logs window object, if we don't use "that"
}();
}
}
myObject.myMethod(); // invoke myMethod
</script></body></html>

控制this的值

this的值通常取决于调用函数的上下文(除非使用关键字new,稍后会为你介绍),但是你可以用apply()或call()指定触发一个函数时this指向的对象,以改变/控制this的值。用这两种方法就好像再说:“嘿,调用X函数,但让Z对象来作this的值。”这样做,JavaScript默认的this的值将被更改。

下面,我们创建了一个对象和一个函数,然后我们通过call()来触发函数,所以函数中的this指向的是myOjbect。在myFunction函数中的this会操作myObject而不是head对象,这样我们就改变了在myFunction中this指向的对象。

<!DOCTYPE html><html lang="en"><body><script>
var myObject = {};
var myFunction = function(param1, param2) {
//setviacall()'this'points to my Object when function is invoked
this.foo = param1;
this.bar = param2;
console.log(this); //logs Object{foo = 'foo', bar = 'bar'}
};
myFunction.call(myObject, 'foo', 'bar'); // invoke function, set this value to myObject
console.log(myObject) // logs Object {foo = 'foo', bar = 'bar'}
</script></body></html>

在上面的例子,我们用了call(),apply()也可适用于同样用法,二者的不同之处在于参数如何传给函数。用call(),参数用逗号分开,而用apply(),参数放在一个数组中传递。下面是同样的代码,但是用apply()。

<!DOCTYPE html><html lang="en"><body><script>
var myObject = {};
var myFunction = function(param1, param2) {
//set via apply(), this points to my Object when function is invoked
this.foo=param1;
this.bar=param2;
console.log(this); // logs Object{foo='foo', bar='bar'}
};
myFunction.apply(myObject, ['foo', 'bar']); // invoke function, set this value
console.log(myObject); // logs Object {foo = 'foo', bar = 'bar'}
</script></body></html>

在自定义构造函数中用this

当函数用关键字new来触发,this的值–由于在构造函数中声明–指向实例本身。换种说法:在构造函数中,我们可以在对象真正创建之前,就用this来指定对象。这样看来,this值的更改和call()或apply()相似。

下面,我们构造了一个构造函数Person,this指向创建的对象。当Person的对象创建后,this指向这个对象,并将属性name放在对象内,值为传给这个构造函数的参数值(name)。

<!DOCTYPE html><html lang="en"><body><script>
var Person = function(name) {
this.name = name || 'johndoe'; // this will refer to the instanc ecreated
}
var cody = new Person('Cody Lindley'); // create an instance, based on Person constructor
console.log(cody.name); // logs 'Cody Lindley'
</script></body></html>

这样,当用关键字new触发构造函数时,this指向“要创建的对象”。那么如果我们没有用关键字new,this的值将会指向触发Person的上下文——这时是head对象。让我们来看看下面的代码。

<!DOCTYPE html><html lang="en"><body><script>
var Person = function(name) {
this.name=name||'johndoe';
}
var cody = Person('Cody Lindley'); // notice we did not use 'new'
console.log(cody.name); // undefined, the value is actually set at window.name
console.log(window.name); // logs 'Cody Lindley'
</script></body></html>

在prototype方法内的this指向构造实例

当一个方法作为一个构造函数的prototype属性时,这个方法中的this指向触发方法的实例。这里,我们有一个Person()的构造函数,它需要person的全名(full name),为了获得全名(full name),我们在Person.prototype中加入了一个whatIsMyFullName方法,所有的Person实例都继承该方法。这个方法中的this指向触发这个方法的实例(以及它的属性)。

下面我创建了两个Person对象(cody和lisa),继承的whatIsMyFullName方法包含的this就指向这个实例。

<!DOCTYPE html><html lang="en"><body><script>
var Person = function(x){
if(x){this.fullName = x};
};
Person.prototype.whatIsMyFullName = function() {
return this.fullName; // 'this' refers to the instance created from Person()
}
var cody = new Person('cody lindley');
var lisa = new Person('lisa lindley');
// call the inherited whatIsMyFullName method, which uses this to refer to the instance
console.log(cody.whatIsMyFullName(), lisa.whatIsMyFullName());
/* The prototype chain is still in effect, so if the instance does not have a
fullName property, it will look for it in the prototype chain.
Below, we add a fullName property to both the Person prototype and the Object
prototype. See notes. */
Object.prototype.fullName = 'John Doe';
var john = new Person(); // no argument is passed so fullName is not added to instance
console.log(john.whatIsMyFullName()); // logs 'John Doe'
</script></body></html>

在prototype对象内的方法里使用this,this就指向实例。如果实例不包含属性的话,prototype查找便开始了。

提示

- 如果this指向的对象不包含想要查找的属性,那么这时对于任何属性都适用的法则在这里也适用,也就是,属性会沿着prototype链(prototype chain)上“寻找”。所以在我们的例子中,如果实例中不包含fullName属性,那么fullName就会查找Person.prototype.fullName,然后是Object.prototype.fullName。

查看更多JavaScript的语法,大家可以关注:《JavaScript 参考教程》、《JavaScript代码风格指南》,也希望大家多多支持我们。

(0)

相关推荐

  • 再次谈论Javascript中的this

    一直对Javascript中的this都有一种似是而非的感觉,今天突然感觉豁然开朗,特此记录一下. 咱们先看个栗子: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>this的使用</title> <script type="text/javascript"> var Car,tesla; Car=functio

  • JavaScript中this的四个绑定规则总结

    前言 如果要问javascript中哪两个知识点容易混淆,作用域查询和this机制绝对名列前茅.所以这篇文章开始将介绍javascript中this的四个绑定规则,下面来一起看看吧. 绑定规则 1. 默认绑定 独立函数调用时,this 指向全局对象,如果使用严格模式,那么全局对象无法使用默认绑定, this绑定至 undefined. function foo() { console.log(this.a); } var a = 2; foo(); // 2 严格模式时: function fo

  • JavaScript中的this,call,apply使用及区别详解

    学习起因: 在之前的JavaScript学习中,this,call,apply总是让我感到迷惑,但是他们的运用又非常的广泛.遂专门花了一天,来弄懂JavaScript的this,call,apply. 中途参考的书籍也很多,以<JavaScript设计模式与开发实践>为主,<JavaScript高级程序设计>.<你不知道的JavaScript>为辅.这三本书对我理解this,call,apply都起了很大的帮助. this 首先,我们先讲述this. 在<Java

  • Javascript中this绑定的3种方法与比较

    介绍 this 可以说是 javascript 中最耐人寻味的一个特性,学习this 的第一步就是明白 this 既不是指向函数自身也不指向函数的作用域. this 实际上是在函数被调用时发生的绑定,它指向什么地方完全取决于函数在哪里被调用. 为什么需要绑定this this代指当前的上下文环境,在不经意间容易改变: var info = "This is global info"; var obj = { info: 'This is local info', getInfo: ge

  • 聊一聊JS中this的指向问题

    JS中的this指向一直是个让人头疼的问题,想当初我学的是天昏地暗,查了好多资料,看的头都大了,跟他大战了那么多回合,终于把它搞定个七八分,其实往往都是我们复杂化了,现在就让大家轻松看懂this的指向,我会分以下几种情况来说. this的指向: 1.this 指的是调用当前方法(函数)的那个对象,也就是说函数在谁那被调用,this就指的是谁. 来看两个栗子: oBtn.onclick = function(){ alert(this); //oBtn } oBtn[i].onclick = fn

  • 学习掌握JavaScript中this的使用技巧

    tip 首先,我知道这篇文章很无聊,无非就是关于 js 中的 this,并且也已经有千千万万的文章写过这部分内容了:  但是,我还是想写一篇关于 js 中的 this 的文章,算是一个总结归纳吧:(大神们可以绕行看我的其他文章)  在 js 中,this 这个上下文总是变化莫测,很多时候出现 bug 总是一头雾水,其实,只要分清楚不同的情况下如何执行就 ok 了. 全局执行 首先,我们在全局环境中看看它的 this 是什么:  first. 浏览器: console.log(this); //

  • javascript this详细介绍

    this的值是在运行时确定的 JS中的this究竟代表什么,这是在程序运行时根据上下文环境确定,可以分为以下几种情况. 1. 全局作用域中的this 在全局作用域中,this指向window对象. console.log(this);//指向window对象 this.x = 5//在全局作用域内创建一个x //与this.x = 5的等价情况: //var x = 5; //x = 5; 在全局作用域中执行var x=5,其实是为window对象创建一个属性x,并令其等于5. 若定义变量时不加

  • JavaScript中的this使用详解

    其实this是一个老生常谈的问题了.关于this的文章非常多,其实我本以为自己早弄明白了它,不过昨天在做项目的过程中,还是出现了一丝疑惑,想到大概之前在JavaScript weekly里收藏待看的一篇详解this的文章(后有链接,也附上了稀土上的中文译文)和另一篇一位前辈推荐的文章,就把它们看了看,对this的认识确实提升了一些. JavaScript 中的'this'是动态的,它在函数运行时被确定而非在函数声明时被确定.所有的函数都可以调用'this',这无关于该函数是否属于某个对象.关于t

  • 探索Javascript中this的奥秘

    前言: this 是 JavaScript 比较特殊的关键字,运用的地方之广,方式之灵活奠定了它的强大,但同时注定了它的难用 .自己刚开始学的时候被绕的很晕,为了彻底弄懂它查了很多资料.然后将自己学的东西整理了一下,以通俗易懂的方式表达出来,权当做学习笔记,同时也可以给有需要的童鞋做下参考^_^ 什么是this? this 关键字的含义是明确且具体的,即指代当前对象.即意味着这个 this 是在某种相对情况下才成立的. this 被分为三种情况:全局对象.当前对象或者任意对象;判断处于那种情况,

  • 实例浅析js的this

    js的this是什么?关于这个东西,博客园里面有太多的解释了,不过,本人看了一下,感觉对this解释的有点复杂了,因此,本人在此给this一个简单易于理解的定义. this其实是js的一个对象,至于是什么对象呢?很简单,this这个对象就是:谁调用它它就指向谁. 关于这一点,其实,博客园的文章已经说明了很多了,有的文章也说到了点子上,只不过,他们解释的还是有点模糊,这里,我给大家做几个简单的对照实验,根据这几个对照实验的结果,大家应该很清楚了. 希望大家根据我的代码重复实现下面的实验. 首先,我

  • 几句话带你理解JS中的this、闭包、原型链

    原型链 所有对象都是基于Object.prototype,Object.prototype就是JavaScript的根对象,在Object.prototype中定义的方法都可以被其它对象访问到,当然也可以被重写了,所以直接在Object.prototype上调用的是原始功能的toString()方法,该方法会放回参数对象的内置属性[[class]]的值,这个值是个字符串,比如'[Object String]' 要理解原型链机制的话,首先得知道根本原因:JavaScript中的对象都有一个内置属性

  • 老生常谈 js中this的指向

    在js中this的指向对于新手来说一定是个难题,但是如果你真正理解了的话,也就没什么问题啦,下面就来讲讲this吧. JS中,this的值取决于调用的模式(调用对象),而JS中共有4种调用模式: 1.函数调用模式 当一个函数不是一个对象的属性时,当作函数俩调用,这时函数内的this指向全局对象(大对数情况下是window) window.value=1; function getValue(){ console.log(this.value); } getValue();//输出1,此时的thi

  • JS中改变this指向的方法(call和apply、bind)

    this是javascript的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. this一般指向的是当前被调用者,但也可以通过其它方式来改变它的指向,下面将介绍三种方式: 1.call用作继承时: function Parent(age){ this.name=['mike','jack','smith']; this.age=age; } function Child(age){ Parent.call(this,age);

随机推荐