晚上咳嗽吃什么药| 两岁宝宝不会说话但什么都知道| 汗手是什么原因| 水泡型脚气用什么药| 肺热吃什么药| tpa是什么意思| 蠢是什么意思| 马提尼是什么酒| 坐东北朝西南是什么宅| 拉不出屎是什么原因| 失聪是什么意思| 无间道是什么意思| 强迫症是什么意思| 拔了牙可以吃什么| 看见黄鼠狼有什么预兆| 右眼皮上长痣代表什么| 为什么有眼袋是什么原因引起的| 木耳中毒什么症状| 兼性厌氧是什么意思| 潮汐车道什么意思| 星芒是什么意思| 什么是凌汛| michaelkors是什么牌子| 为什么小鸟站在电线上不会触电| 头孢是治疗什么病的| 既往病史是什么意思| 1月20是什么星座| 前面有个豹子是什么车| 手淫对身体有什么伤害| 半斤八两什么意思| 日光性皮炎用什么药| 卵泡回声什么意思| 九知道指的是什么| 中人是什么意思| 内在美是什么意思| 芒果是什么意思| 嗓子痒吃什么药| 武火是什么意思| 湿气重吃什么能去湿气| 顽固不化是什么意思| 群星是什么意思| 天人合一是什么意思| 鼻梁高的男人说明什么| 一个雨一个亏念什么| 番外是什么意思| 为什么会长息肉| 人到无求品自高什么意思| 肺主皮毛是什么意思| 血糖高喝酒有什么影响| 打呼噜是什么原因引起的| 高血压突然变成低血压是什么原因| 女性感染梅毒有什么症状| 什么时间喝酸奶最好| 一个米一个参念什么| 状元是什么官| 胃疼吃什么食物对胃好| 专技十三级是什么意思| pt950是什么材质| 轻奢是什么意思| 白羊座的幸运色是什么| 女人的逼长什么样| 误会是什么意思| 香客是什么意思| 女人银屑病一般都长什么地方| 95年猪五行属什么| 舌苔厚是什么原因引起的| 放血有什么好处| 牙疼不能吃什么东西| 两个子是什么字| 中出什么意思| 咳黄痰吃什么药| 什么药补气血效果最好| 卷柏是什么植物| 肝化灶是什么意思| 嘌呤高会引起什么症状| 女生右手中指戴戒指什么意思| 碱性磷酸酶偏低是什么意思| 鹅喜欢吃什么草| 子婴是秦始皇什么人| 左肾轻度积水是什么意思| 氟利昂是什么味道| 什么原因会怀上葡萄胎| 中国信仰什么教| 319是什么星座| 真菌是什么| 高锰酸钾是什么东西| 窦性心律过速吃什么药| 鼓刹和碟刹有什么区别| 尿检ph值偏高说明什么| 孙耀威为什么被封杀| kyocera是什么牌子| 什么食物不能一起吃| 吃什么能马上晕倒住院| 肾痛在什么位置痛| 气川读什么| 鼻子两侧毛孔粗大是什么原因造成的| 腰痛应该挂什么科| 军加皮念什么| 儿童过敏性鼻炎吃什么药好| 和是什么意思| 皮肤科属于什么科室| 囫囵吞枣是什么意思| absorb什么意思| 梦见玫瑰花是什么预兆| 规培是什么意思| 男左女右是什么意思| 兽中之王是什么动物| 什么情况| 散佚是什么意思| 什么是基础医学| 头皮屑特别多是什么原因| 牙龈上火是什么原因引起的| 空调除湿是什么标志| 多囊是什么原因引起的| 同房痛什么原因引起的| 荟萃是什么意思| 脂肪瘤吃什么药| 女性排卵有什么症状或感觉| 12月22日什么星座| 什么笑容| 摩纳哥为什么这么富| 秦皇岛有什么特产| 盆腔镜检查是查什么的| 什么是黑天鹅事件| 五行缺金是什么命| 睡觉容易惊醒是什么原因| 房颤吃什么药效果最好| 琋字五行属什么| 吃鱼眼睛有什么好处| 梭织面料是什么面料| 小孩子手足口病有什么症状图片| 背痛去医院挂什么科| y3是什么牌子| ra是什么病| 361是什么意思| 制片人是什么意思| magnesium是什么意思| 梦见好多动物是什么意思| 希特勒为什么要杀犹太人| 来月经胸胀痛什么原因| 大公无私是什么意思| ld是什么意思| 高考600多分能上什么大学| 核糖是什么| 芋圆是什么| 法院院长是什么级别| 测血糖挂什么科| 前门大街有什么好玩的| 精神食粮是什么意思| 吸顶灯什么牌子的好| 3.1是什么星座| 人体成分分析是检查什么| 骨穿是检查什么病| 为什么脚底会脱皮| 水军什么意思| 餐后血糖高吃什么药| husky是什么牌子| 世界上最长的蛇是什么| 什么的拳头| 马蹄铁什么时候发明的| 检查肺部挂什么科室| 痰栓是什么意思| 白鱼又叫什么鱼| 头皮发热是什么原因| bpo是什么意思啊| 吃什么补胰腺最好| 彼岸花又叫什么花| 骨折吃什么恢复快| 泡菜生花用什么方法可以去掉| 85属什么| 鞭炮笋学名叫什么| 3月2日是什么星座| 为什么月经老是提前| hpv16阳性有什么症状| 梦见车丢了是什么意思| 方可以加什么偏旁| 乙肝五项45阳性是什么意思| 养精蓄锐是什么意思| 左手中指痛什么预兆| 重庆市长是什么级别| 今天什么时辰立秋| 头晕用什么药好| 龙眼什么时候成熟| 食指发麻是什么原因| 泡脚对身体有什么好处| 做梦梦到剪头发是什么意思| 肚脐眼发炎是什么原因| 阳痿吃什么药| 脖子粗是什么原因| iac是什么意思| balea是什么牌子| 经期血块多是什么原因| 补蛋白吃什么最好| 内膜增生是什么意思| 什么的水花| 开除公职是什么意思| 新加坡为什么说中文| 新生儿超敏c反应蛋白高说明什么| 促甲状腺激素偏低是什么意思| 脾虚吃什么中药| 焦虑症是什么意思| 齐白石擅长画什么| 牙根变黑是什么原因| 蝉是什么意思| 西瓜禁忌和什么一起吃| 自闭症是什么原因引起| 碳酸氢钠是什么添加剂| 泉州有什么特产| 仙草是什么| 何首乌泡酒有什么作用| fredperry是什么牌子| 老九门讲的是什么故事| 什么原因会怀上葡萄胎| 血糖高是什么症状| 清洁度1度是什么意思| pray是什么意思| 夏季吃什么菜| 嫌疑人是什么意思| 左腹下方隐痛什么原因| 兔子的耳朵像什么| 风热感冒用什么药| 草菅人命是什么意思| 顺位是什么意思| 补气血吃什么药效果好| 胃复安又叫什么| 狗狗皮肤病用什么药| 手脚发麻是什么病征兆| 澳门车牌号是什么样子| 脸上突然长斑是什么原因引起的| 卵巢囊肿术后吃什么食物好| 喝生鸡蛋有什么好处| 茶叶渣属于什么垃圾| 每天泡脚对身体有什么好处| 藏青色是什么颜色| 罗字五行属什么| 嗔什么意思| 胳膊困疼是什么原因| hl是什么意思| 牙龈萎缩吃什么药见效快| 剩女什么意思| 为什么有眼袋是什么原因引起的| 心什么如什么的成语| 袁字五行属什么| 藕粉对身体有什么好处| 发烧吃什么食物最好| 排卵试纸什么时候测最准确| 孕妇梦见老鼠是什么意思| 龟苓膏有什么作用| 小腹胀痛是什么原因| nilm是什么意思| 亲子鉴定需要什么样本| penis什么意思| 3月3日什么星座| 什么是萎缩性胃炎| 违和是什么意思| 梦见大领导有什么预兆| 凤凰单丛属于什么茶| 手淫过度有什么症状| 世界七大奇迹分别是什么| 卤肉是什么肉| pda医学上是什么意思| 腰间盘突出压迫神经什么症状| 头疼想吐吃什么药| 1月23日是什么星座| 百度

保护知识产权服务社会发展

decent programming advice

written by ben cherry




JavaScript Scoping and Hoisting

百度 每年纷至沓来的游人们往往会在巴黎圣母院的入口附近停下来,寻找人行道上镶嵌的一颗青铜星星——法国道路的零起点。

Do you know what value will be alerted if the following is executed as a JavaScript program?

var foo = 1;
function bar() {
	if (!foo) {
		var foo = 10;
	}
	alert(foo);
}
bar();

If it surprises you that the answer is “10”, then this one will probably really throw you for a loop:

var a = 1;
function b() {
	a = 10;
	return;
	function a() {}
}
b();
alert(a);

Here, of course, the browser will alert “1”. So what’s going on here? While it might seem strange, dangerous, and confusing, this is actually a powerful and expressive feature of the language. I don’t know if there is a standard name for this specific behavior, but I’ve come to like the term “hoisting”. This article will try to shed some light on this mechanism, but first lets take a necessary detour to understand JavaScript’s scoping.

Scoping in JavaScript

One of the sources of most confusion for JavaScript beginners is scoping. Actually, it’s not just beginners. I’ve met a lot of experienced JavaScript programmers who don’t fully understand scoping. The reason scoping is so confusing in JavaScript is because it looks like a C-family language. Consider the following C program:

#include <stdio.h>
int main() {
	int x = 1;
	printf("%d, ", x); // 1
	if (1) {
		int x = 2;
		printf("%d, ", x); // 2
	}
	printf("%d\n", x); // 1
}

The output from this program will be 1, 2, 1. This is because C, and the rest of the C family, has block-level scope. When control enters a block, such as the if statement, new variables can be declared within that scope, without affecting the outer scope. This is not the case in JavaScript. Try the following in Firebug:

var x = 1;
console.log(x); // 1
if (true) {
	var x = 2;
	console.log(x); // 2
}
console.log(x); // 2

In this case, Firebug will show 1, 2, 2. This is because JavaScript has function-level scope. This is radically different from the C family. Blocks, such as if statements, do not create a new scope. Only functions create a new scope.

To a lot of programmers who are used to languages like C, C++, C#, or Java, this is unexpected and unwelcome. Luckily, because of the flexibility of JavaScript functions, there is a workaround. If you must create temporary scopes within a function, do the following:

function foo() {
	var x = 1;
	if (x) {
		(function () {
			var x = 2;
			// some other code
		}());
	}
	// x is still 1.
}

This method is actually quite flexible, and can be used anywhere you need a temporary scope, not just within block statements. However, I strongly recommend that you take the time to really understand and appreciate JavaScript scoping. It’s quite powerful, and one of my favorite features of the language. If you understand scoping, hoisting will make a lot more sense to you.

Declarations, Names, and Hoisting

In JavaScript, a name enters a scope in one of four basic ways:

  1. Language-defined: All scopes are, by default, given the names this and arguments.
  2. Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
  3. Function declarations: These are of the form function foo() {}.
  4. Variable declarations: These take the form var foo;.

Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter. Function parameters and language-defined names are, obviously, already there. This means that code like this:

function foo() {
	bar();
	var x = 1;
}

is actually interpreted like this:

function foo() {
	var x;
	bar();
	x = 1;
}

It turns out that it doesn’t matter whether the line that contains the declaration would ever be executed. The following two functions are equivalent:

function foo() {
	if (false) {
		var x = 1;
	}
	return;
	var y = 1;
}
function foo() {
	var x, y;
	if (false) {
		x = 1;
	}
	return;
	y = 1;
}

Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted. This is not the case with function declarations, where the entire function body will be hoisted as well. But remember that there are two normal ways to declare functions. Consider the following JavaScript:

function test() {
	foo(); // TypeError "foo is not a function"
	bar(); // "this will run!"
	var foo = function () { // function expression assigned to local variable 'foo'
		alert("this won't run!");
	}
	function bar() { // function declaration, given the name 'bar'
		alert("this will run!");
	}
}
test();

In this case, only the function declaration has its body hoisted to the top. The name ‘foo’ is hoisted, but the body is left behind, to be assigned during execution.

That covers the basics of hoisting, which is not as complex or confusing as it seems. Of course, this being JavaScript, there is a little more complexity in certain special cases.

Name Resolution Order

The most important special case to keep in mind is name resolution order. Remember that there are four ways for names to enter a given scope. The order I listed them above is the order they are resolved in. In general, if a name has already been defined, it is never overridden by another property of the same name. This means that a function declaration takes priority over a variable declaration. This does not mean that an assignment to that name will not work, just that the declaration portion will be ignored. There are a few exceptions:

  • The built-in name arguments behaves oddly. It seems to be declared following the formal parameters, but before function declarations. This means that a formal parameter with the name arguments will take precedence over the built-in, even if it is undefined. This is a bad feature. Don’t use the name arguments as a formal parameter.
  • Trying to use the name this as an identifier anywhere will cause a SyntaxError. This is a good feature.
  • If multiple formal parameters have the same name, the one occurring latest in the list will take precedence, even if it is undefined.

Named Function Expressions

You can give names to functions defined in function expressions, with syntax like a function declaration. This does not make it a function declaration, and the name is not brought into scope, nor is the body hoisted. Here’s some code to illustrate what I mean:

foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
spam(); // ReferenceError "spam is not defined"

var foo = function () {}; // anonymous function expression ('foo' gets hoisted)
function bar() {}; // function declaration ('bar' and the function body get hoisted)
var baz = function spam() {}; // named function expression (only 'baz' gets hoisted)

foo(); // valid
bar(); // valid
baz(); // valid
spam(); // ReferenceError "spam is not defined"

How to Code With This Knowledge

Now that you understand scoping and hoisting, what does that mean for coding in JavaScript? The most important thing is to always declare your variables with a var statement. I strongly recommend that you have exactly one var statement per scope, and that it be at the top. If you force yourself to do this, you will never have hoisting-related confusion. However, doing this can make it hard to keep track of which variables have actually been declared in the current scope. I recommend using JSLint with the onevar option to enforce this. If you’ve done all of this, your code should look something like this:

/*jslint onevar: true [...] */
function foo(a, b, c) {
    var x = 1,
    	bar,
    	baz = "something";
}

What the Standard Says

I find that it’s often useful to just consult the ECMAScript Standard (pdf) directly to understand how these things work. Here’s what it has to say about variable declarations and scope (section 12.2.2 in the older version):

If the variable statement occurs inside a FunctionDeclaration, the variables are defined with function-local scope in that function, as described in section 10.1.3. Otherwise, they are defined with global scope (that is, they are created as members of the global object, as described in section 10.1.3) using property attributes { DontDelete }. Variables are created when the execution scope is entered. A Block does not define a new execution scope. Only Program and FunctionDeclaration produce a new scope. Variables are initialised to undefined when created. A variable with an Initialiser is assigned the value of its AssignmentExpression when the VariableStatement is executed, not when the variable is created.

I hope this article has shed some light on one of the most common sources of confusion to JavaScript programmers. I have tried to be as thorough as possible, to avoid creating more confusion. If I have made any mistakes or have large omissions, please let me know.

filed under javascript

耳塞戴久了有什么危害 kms是什么药 mfg是什么意思 三轮体空什么意思 儿童乳房发育挂什么科
紫外线过敏用什么药 梦见被雨淋是什么意思 藏红花适合什么样的人喝 溯溪是什么意思 hpf医学是什么意思
三个女人一台戏什么意思 日落是什么时辰 梦见梳头发是什么意思 什么是甲减有什么症状 前壁后壁有什么区别
神经衰弱什么症状 二甲双胍缓释片什么时候吃 无水酥油是什么油 虹膜是什么意思 北京有什么特产好吃
睡不着是什么原因hcv9jop8ns0r.cn 最新病毒感染什么症状hcv8jop7ns8r.cn 葬爱家族是什么意思hcv7jop9ns5r.cn 什么叫唐卡imcecn.com 便秘挂什么科室dayuxmw.com
再接再励是什么意思hcv9jop6ns1r.cn 县长什么级别干部jasonfriends.com 落马是什么意思hcv8jop8ns1r.cn 精不液化是什么原因导致的hcv9jop8ns1r.cn 蜥蜴什么动物hcv9jop2ns2r.cn
火牙是什么原因引起的hcv8jop6ns2r.cn 造化弄人是什么意思hcv9jop6ns0r.cn 三点水加累读什么hcv8jop3ns0r.cn 脐炎用什么药hcv9jop0ns4r.cn 胃糜烂吃什么药hcv8jop9ns4r.cn
铁低的原因是什么hcv7jop4ns8r.cn 克服是什么意思weuuu.com 此物非彼物是什么意思hcv8jop8ns5r.cn 梦见别人买房子是什么预兆hcv9jop8ns1r.cn 不排卵是什么原因hcv8jop2ns3r.cn
百度