`
该用户名已经存在
  • 浏览: 306573 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多
这篇文章中已经简单的提到了函数和变量提升的概念。下面将更加仔细的阐述Javascript中的变量和函数的提升。


一、变量和函数提升的现象
首先思考下面的代码执行后将打印出什么?
var foo = 1;
function bar()
{
	if (!foo) 
	{
		var foo = 10;
	}
	alert(foo);
}
bar();

如果这个结果("10")会让你感到惊讶,那么下面的例子会不会也会让你同样的惊讶:
var a = 1;
function b() 
{
	a = 10;
	return;
	function a() {}
}
b();
alert(a);

没错,浏览器将打印"1"。这里面到底发生了什么?这看起来似乎很奇怪,危险而且很迷惑,
这事实上就是Javascript这门语言强大的、具有表现力的功能。以上的现象没有一个标准的名字,姑且就叫其为“提升”,这篇文章主要就是讲解一下Javascript的这一机制,但是在学习提升之前我们首先要了解一下Javascript的“域”,这样才能更好的理解提升。

二、Javascript的域
对于Javascript的初学者来讲,域是学习Javascript最大的疑惑,事实上很多熟练的Javascript开发人员也不是能完全的理解域,域在Javascript中如此具有迷惑性的原因是它看起来像C族语言,考虑以下的C代码:
#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
}

以上代码将依次输出1,2,1,这是因为C以及其他C族语言拥有“块级域”(block-level scope)。当控制语句进入一个块,比如if语句块,我们能在这个块中声明新的变量,而不会影响外部的“域”。但在Javascript中并不是这样的,尝试在FireFox中运行以下代码:
var x = 1;
console.log(x); // 1
if (true) {
	var x = 2;
	console.log(x); // 2
}
console.log(x); // 2

以上FireFox将打印1,2,2,这是因为Javascript拥有“函数级域”(function-level scope),这是和C族语言根本上的不同,像if语句这样的块不能形成一个新的域,只有函数能创建新的域。对于很多曾经喜欢使用C,C++,C#或者Java的程序员来讲,这种现象是不希望也是不受欢迎的。幸运的是由于Javascript函数的灵活性,这一现象是可以得到弥补的,如果非要在一个函数里面再创建一个临时域,看以下例子:
function foo() {
	var x = 1;
	if (x) {
		(function () {
			var x = 2;
			// some other code
		}());
	}
	// x is still 1.
}

这个方法实际上非常的灵活,而且能够在任何你需要使用临时域的地方使用这种方法,不仅仅是在语句块中。强烈建立大家真正的花时间去理解和领会Javascript的域。它非常的强大,如果你理解了Javascript的域和提升,对你非常有意义的。

三、声明,命名和提升
在Javascript中,一个名字在一个域中创建可以通过以下四个方式之一:
1.语言自身的定义:默认所有的域都被给予this和arguments两个命名。
2.正式的参数:函数提供的域中会为该函数参数提供命名。
3.函数声明:函数提供的域会为函数体内声明的其他函数提供命名。
4.变量声明:函数提供的域会为函数体内声明的变量提供命名。
函数声明和变量声明常常会被Javascript解释器隐形的提升到包含它们的域的顶部,这就意味着像一下的代码:
function foo() {
	bar();
	var x = 1;
}

实际上更像是这样被解读的:
function foo() {
	var x;
	bar();
	x = 1;
}

这就说明,我们声明变量或者函数的那一行语句会不会被执行是没有关系的。什么意思呢?就是以下两个函数是等效的:
function foo() {
	if (false) {
		var x = 1;
	}
	return;
	var y = 1;
}
function foo() {
	var x, y;
	if (false) {
		x = 1;
	}
	return;
	y = 1;
}

需要注意的是:变量初始化的部分并没有被提升,只是变量声明的部分被提升。但是对于函数来说有两种形式:函数声明和函数表达式。对于函数表达式是和变量一样的,但对于函数声明,是将整个函数体一起提升的:
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();

这就是提升的基本原则,没有想象中的那么奇怪和复杂。其实提升的本质还是《Javascript的函数和执行环境》
一文中讲到的Javascript的执行环境的创建问题,提升只是我们看到的直观的现象,如果要深入了解提升的本质,请参考该文。

良好的编码习惯,由于Javascript的变量提升的语言特点,如果我们在函数中到处声明变量,那完全是自讨苦吃,既然我们在哪儿声明变量都会被Javascript解释器隐式的提升到最顶部,我们为什么不直接在函数的最顶部声明我们的变量或者函数,这样既直观,看起来也整洁,也不至于产生混淆,会避免很多不必要的麻烦。
/*jslint onevar: true [...] */
function foo(a, b, c) {
	var x = 1,
		bar,
		baz = "something";
}
分享到:
评论

相关推荐

    深入理解Javascript作用域与变量提升

    主要是对Javascript作用域与变量提升进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助

    JavaScript 变量提升 | 执行上下文 | 作用域

    JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。变量可以在使用后声明,也就是变量可以先使用再声明。 声明了a,没声明b,输出a不会报错,但是输出b会报错==&gt;变量可以先使用再声明。 变量的提升只会把...

    JavaScript核心概念及实践 高清PDF扫描版 (邱俊涛).pdf

    《JavaScript核心概念及实践》不仅帮助读者迅速掌握JavaScript基础知识和核心技术,而且通过实例讲解如何将这些知识和技术理解应用到实际工作中,提升编程能力,以简洁、优美的代码开发出功能强大且更易于维护和扩展...

    JavaScript 作用域scope简单汇总

    什么是作用域 程序的执行,离不开作用域,也必须在...在JavaScript变量提升的讨论中,我们其实是缺少了一个作用域的概念的,变量提升其实也是针对在同一作用域中的代码来说的。 对编译器的了解,让我们明白,对于一段

    详解javascript中的变量提升和函数提升

    那么变量提升就是变量声明会被提升到作用域的最顶上去,也就是该变量不管是在作用域的哪个地方声明的,都会提升到作作用域的最顶上去。 那么上面这种写法其实等价于下面这种写法: 看几个例子: 把上面的例子稍作...

    JavaScript面试揭秘:掌握这些高频题,轻松征服面试官!.zip

    理解JavaScript的作用域链、闭包和原型链等核心概念 掌握JavaScript事件冒泡与捕获的原理和区别 学会使用ES6新特性,提升代码质量和开发效率 理解JavaScript异步编程的原理,掌握Promise和async/a

    JavaScript中变量提升和函数提升的详解

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升。这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下。 今天主要介绍以下几点: 1. 变量提升 2. 函数提升 3....

    JavaScript中Hoisting详解 (变量提升与函数声明提升)

    其实 Hoisting(提升) 这个词是用来解释 变量 和 函数声明 是如何被提升到 函数或全局 作用域顶部的。你在任何的 JavaScript 文档中找不到这个术语,我们说的 Hoisting(提升) 只是使用了其字面含义来做个比喻。 如果...

    javascript中的变量作用域以及变量提升详细介绍

    变量作用域分为局部作用域和全局作用域。 局部变量(处于函数级别的作用域)不像其他对面对象的编程语言(比方说C++,Java等等),javascript没有块级作用域(被花括号包围的);当是,javascript有拥有函数级别的...

    JavaScript变量提升和严格模式实例分析

    本文实例讲述了JavaScript变量提升和严格模式。分享给大家供大家参考,具体如下: 1.什么是变量提升 所谓的变量提升指的是:函数声明和变量声明总是会被解释器悄悄地被”提升”到方法体(作用域)的最顶部。 下面我们...

    JavaScript高级整理

    谷粒学院学习笔记,内容包括 原型与原型链、执行上下文、执行上下文栈、变量提升、函数提升、作用域、作用域链、闭包、对象的多种创建模式、对象的继承模式、JavaScript事件循环机制等。

    JavaScript王者归来part.1 总数2

     1.7 学习和使用JavaScript的几点建议   1.8 关于本书的其余部分   第2章 浏览器中的JavaScript  2.1 嵌入网页的可执行内容   2.2 赏心悦目的特效   2.3 使用JavaScript来与用户交互  2.4 绕开脚本陷阱 ...

    10-作用域链和闭包:代码中出现相同的变量,JavaScript引擎是如何选择的?_For_vip_user_0011

    在上篇章中我们讲到了什么是作域,以及ES6是如何通过变量环境和词法环境来同时持变量提升和块级作域,在最后我们也提到了如何通过词法环境和变量环境来查找变量,这其中

    JavaScript中最容易混淆的作用域、提升、闭包知识详解(推荐)

    在web前端开发中js中的作用域,提升,闭包知识是经常用到的也是很容易混淆的知识点,接下来小编整理了本教程帮助大家学习

    关于JavaScript中var声明变量作用域的推断

    一、迷思!由一段代码引发的疑惑 请看如下代码: 代码如下: for... 如果JavaScript中用var声明的变量可视为局部变量,那么能访问到这个变量的作用域就是这个变量的局部作用域。如上例,在console.log行处,依然有j、k

    JS中作用域和变量提升(hoisting)的深入理解

    相信大家也都发现了,在网上关于JS的变量和作用域的文章有很多,但真正能讲清楚,能深入理解的文章很少。在阅读了很多人的文章以后,我决定综合起来,结合实际代码,希望能够以一个比较清楚完整的方式让大家真正理解...

Global site tag (gtag.js) - Google Analytics