关于《JavaScript高级程序设计(第2版)》中的一句话
2010年05月8日 Web开发, 原创, 翻译
第5章中有这样一句话:“this是函数在执行时所处的作用域”(《JavaScript高级程序设计(第2版)》第5章5.5.4节正文倒数第3段中)。我觉得作者的这种说法大有问题。对JavaScript不熟悉的读者会越看越糊涂。这里首先需要明确两个概念:函数执行时所处的作用域、在哪个作用域中调用函数函数调用发生的作用域,否则讨论就无法继续深入。把后一概念明确为“函数调用语句所处的那个作用域”应该没有问题。而前一个概念,实际上就是函数的定义所处的那个作用域。以下面的代码为例:
function a() {
// ...
}
function b() {
/// ...
return function c() {
// ...
};
}
var d = b();
a();
d();
在这里,函数a、b和d(实际上就是c)都是在全局作用域中调用的。a和b执行时所处的作用域都是全局作用域。但是d执行时所处的作用域并不是全局作用域,而是函数b的局部作用域。说到这里,就可以看到“this是函数在执行时所处的作用域”这一说法的不妥了。假如函数c中引用到了this(在本例中,d是直接调用的,所以this指向的是全局对象),那么按作者的说法,c 岂不是直接运行在全局作用域中而不是b的局部作用域中了?再看下述例子:
var greeting = 'Hello from global scope!';
function e() {
alert(greeting);
alert(this.greeting);
}
var tom = {
greeting:'Hello from Tom!'
};
tom.f = e;
tom.f();
这个例子中的this指向的是什么?显然是tom。那么f(即e)执行时所处的作用域是什么?显然是全局作用域。假如f执行时所处的作用域如作者所说为this所指对象的话,那就意味着在本例中f执行时所处的作用域为tom,也就是说在f执行过程中,与其作用域链相对应的那个变量对象链的最前端那个对象是tom,而这就意味着在此时函数体内对名称greeting进行解析时首先遇到的是tom中定义的greeting,于是两条输出语句的结果都应该是“Hello from Tom!”,这不符合事实,所以按作者的说法所做的那个假设是错误的。
对于this这个关键字,我认为不应该扯什么作用域的事儿,只要向读者说明以下几项这样一句话就够了:函数作为哪个对象的方法调用,函数体内的this(不包括嵌套定义在其中的函数中的this)指向的就是那个对象。直接调用一个函数,相当于把它当作全局对象的方法调用。JavaScript 中没有类作用域的概念,因此方法内部要访问据以调用此方法的那个对象的属性,必须使用this关键字,按‘this.属性名’的语法来访问
- 函数作为哪个对象的方法调用,函数体内的this(不包括嵌套定义在其中的函数中的this)指向的就是那个对象。
- 结合new运算符调用一个构造函数时,系统会先自动生成一个对象,然后在该对象上调用构造函数。此时在构造函数体内,this指向的就是这个对象。
- 直接调用一个函数,相当于把它当作全局对象的方法调用。
- JavaScript中没有类作用域的概念,因此方法内部要访问据以调用此方法的那个对象的属性,必须使用this关键字,按“this.属性名”的语法来访问。
与这个问题相关的还有一个函数体内的名称解析的问题。我看过的JavaScript教材上都说得不太全面。实际上,那种直接引用的名称,其名称解析是在作用域链上进行的;而那种按“obj.属性名”方式引用的名称,其名称解析是在obj的原型对象链上进行的(首先检查obj是否直接定义了同名属性,如果没有,则在其原型对象链上逐层查找)。理解了这一点,就更能搞清前面的this与作用域的瓜葛。


为之漫笔(李松峰),本博客专注于Web前后端技术、移动平台开发技术、交互设计和技术翻译。声明一下,因为时常需要外出审稿,而且基本不带笔记本,所以有时可能会迟一点回复大家的留言。
Would you be interested by exchanging links?
Wow, I enjoyed your neat post.
There are actually quite a lot of details like that to take into consideration. That is a great point to deliver.
Aw, this was a very nice post. In thought I want to write like this – taking time and actual effort to make an excellent article is very rare…
you have a terrific weblog right here! would you prefer to make some invite posts on my weblog?
I was very pleased to find this website. I wanted to thank you for your time for this wonderful post!! I definitely enjoy reading it and I have you bookmarked to check out new stuff you blog post.
Can I just say what a relief to find someone who actually knows what theyre talking about on the internet.
Rarely do I encounter a blog that’s both educated and entertaining, and let me let you know, you’ve hit the nail on the head. Your thought is excellent; the issue is something that not enough individuals are speaking intelligently about. I’m very happy that I stumbled across this in my search for info regarding this.
very nice post, i certainly love this website, keep on it.
One must mourn not the death of men but their birth. (Charles Scondat Montesquieu, French thinker and Philosopher)
Who has deceiv'd thee so oft as thy self?
This really answered my problem, thank you!
Thanks for your sharing!
Excellent, I just passed this onto a colleague who was doing a little research on that.
我觉得作者说的没有错,
“this引用的是函数据以执行操作的对象–或者也可以说,
this是函数在执行时所处的作用域.”
前半句很好理解,默认定义一个函数,访问这个函数,其this是全局的,
毫无疑问,如果你把这个函数的引用给了别人.那么这个函数的this
也就也就给了别人了.”this引用的是函数,据以执行操作的,对象”.
好好品味一下这句话你就会明白了.
后半句”或者也可以说,this是函数在执行时所处的作用域.”跟前半句
一个意思只是换了一个说法. 个人看法,劳驾!
var greeting = ‘Hello from global scope!’;
window.greeting = “Hello window”;
function e(){
alert(greeting);
alert(this.greeting);
}
e();
var tom = {
greeting: ‘Hello from Tom!’
};
tom.f = e;
tom.f();
I’m still learning from you, but I’m improving myself. I definitely liked reading everything that is written on your blog.Keep the information coming. I liked it!
Hi, the article is so wonderful, I am interested in it. I will pay attention to your articles.
Thank you for your articles!
Welcome to visiting our jerseys .jerseys from china . jerseys sale products are won highly praise from our customers.
our goal is to be popular and fashionable vane,offer the best products and service, the most preferential price.
The decline of literature shows the decline of the nation; the two retain within their downwad tendency. (Johann Wolfgang von Goethe German poet)
我觉得在这里,博主把作用域链与原型链给混淆了。。。具体请看下面的代码:
var val = 'val from global scope';
var Tester = (function(){
var val = 'val from closure scope';
var handler = {
val: 'val from handler',
getVal: function(){
return val;
},
getThisVal: function(){
return this.val;
},
getHandlerVal: function(){
return handler.val;
}
};
return handler;
})();
console.log(Tester.val); // val from handler
console.log(Tester.getVal()); // val from closure scope
console.log(Tester.getThisVal()); // val from handler
console.log(Tester.getHandlerVal()); // val from handler
我也觉得博主你对你举得的例子的说明本身就有问题,有错误
var greeting = ‘Hello from global scope!’;
function e() {
alert(greeting);
alert(this.greeting);
}
var tom = {
greeting:’Hello from Tom!’
};
tom.f = e;
tom.f();
在这里执行tom.f()的时候,相当于就是执行tom的一个方法f。
那么
首先会执行 alert(greeting); 这里的greeting是一个变量。在函数e中并没有这个变量,那么会向上找到全局定义的var greeting = ‘Hello from global scope!’;这一句。
这里没有说明问题呀,怎么会像作者说的会执行 greeting:’Hello from Tom!’这一句呢,这一句是tom的属性。跟alert(greeting);中的greeting完全是两码事。
不知道你是不是这样理解的。先不说原著那句话是不是对的。但是你用这个例子来说明作者的那句话,我觉得你对这个例子的解释就有问题。
个人之见,欢迎批评指正。谢谢
This is a very informative article.I was looking for these things and here I found it. I am doing a project and this information is very useful me. If you are interested in, but this is my duty to inform you that virtual administrative assistant a very dedicated service and can be applied anywhere you want and get better results.
Thanks for sharing,I really like it. I will be back to check some more information on this.
在我看来原书作者的表述是正确的,原书作者明确提到this指向的是运行时的作用域,而博主所列举的第二个例子中的解释是有问题的,”这个例子中的this指向的是什么?显然是tom。那么f(即e)执行时所处的作用域是什么?”这一句里的括号中的“即e”描述是不准确的,在本例中,当函数e和函数f执行时,他们其实是处在不同的作用域中的。不管是e,还是f都只是一个指针,在他们各自的对象不同的时候是不能进行等价的。以上纯属个人见解哈,欢迎博主及各位同行批评指正
I’m still waiting for some interesting thoughts from your side in your next post thanks.
英文第三版出了,有沒有要翻成中文呢?
会翻译的。