变量声明恐怕是我们日常开发中最最经常遇到的了, 那今天我们就来总结下现在 JS 一共有哪几种变量声明的方式以及各个声明方式的特点.
ES5 变量声明方式有 var, function.
通过这两种方式声明的变量特点就是具有 "变量提升" 的效果, 一般想法是一个变量是先声明后使用, 然而如果采用 var 或者 function 声明的变量和函数 (函数表达式不会提升) 具有提升的效果.
下面详细说明变量提升究竟是怎么产生的.
代码在引擎中运行之前都会经历词法分析阶段, 这个阶段会将由字符组成的字符串分解成若干 (对编程语言而言) 有意义的代码块, 而这些小的代码块我们可以称他们为词法单元, 举个栗子给大家, 比如: var age = 27; 这一句通常会被分解为 var,age,=,27,; 空是否会被当做词法单元取决于空格在这门语言中是否有意义. 接下来是语法分析阶段会将这些词法单元解析成一个树结构我们将这个树结构称之为 "抽象语法树". 然后编译器会进行如下处理, 首先遇到 var age, 编译器会询问当前作用域是否已近存在一个改名字的的变量, 如果是的, 编译器就会忽略该声明, 如果不是的话就会要求在当前作用域的集合中声明一个新的变量, 并且为这个变量命名为 age. 但是不会立刻给他赋值, 赋值是在运行的时候才做的事情. 编译阶段实际会吧所有的 var 声明的变量提升到前面. 即 var age = 27; 可以近似的看成 var age;(编译阶段)age = 27;(运行阶段). 所以就会产生 "变量提升" 的效果了.
关于变量提升需要注意这几点:
在 JS 中用 var ,function 声明的变量都将被提到函数的最顶部.(但是不会初始化)
函数声明的优先级大于变量声明的优先级(function> var )
在函数内部变量提升的优先级会小于函数参数(函数参数> 函数内部变量提升)
下面辅以例子来具体说明
- console.log(a)
- var a = 3;
运行结果如下:
undefined
实际上等同于运行下列代码:
- var a;
- console.log(a)
- a = 3;
打印出 a 的时候, a 已近声明 (变量提升的效果) 但是并未赋值, 自然就是 undefined 了, 如果没有变量提升的效果此处就会报一个 reference erro 的错误类型了.
再看如下代码:
- console.log(f)
- f()
- var f = 27;
- function f(){
- console.log('I am function f')
- }
- console.log(f);
- f = 2;
- f();
看看运行结果:
ƒ f(){
- console.log('I am function f')
- }
- I am function f
- 27
- Uncaught TypeError: f is not a function
下面我们来分析一下为什么是这个结果:
先 var 和 function 都具有变量提升且根据我们上面的第二条原则 function> var 所以第一次打印 console.log(f)此时的 f 是一个函数;
接下来是运行 f()自然就会得到 f 函数内打印的字符串'I am function f'再接下来就是给 f 赋值了此时的 f = 27; 打印 f 就会得到数字 27, 然后又将 f 的值改为 2, 再运行 f()而此时 f 已近不是一个函数了, 所以控制台会抱一个 typeError 的错误, 表示我们对 f 的用法错了(关于各个错误类型我们后面会有一篇文章专门说明).
下面再看看我们所说的第三点:
- var age = 0;
- function foo(age) {
- console.log(age);
- var age = 20;
- }
- foo(27)
- console.log(age)
- 27 0
在函数 foo 中此时传入的参数 age=27, 根据我们上述的第三点即函数参数> 函数内部变量提升. 所以在函数内部打印出的 age 是传入的参数 27, 最后一句打印出的 age 自然就是 0 了.
有关于函数表达式是否会有变量提升, 我看了很多人写的博客是说函数表达式并不会有变量提升, 我并不赞同这个观点, 我觉得函数表达式也会产生变量提升, 事实上只要是用 var 与 function 声明的变量都会产生变量声明, 但切记用 var 声明的变量不会立马赋值. 看如下代码.
- console.log(foo)
- var foo = function () {
- console.log('I am a function foo')
- }
- undefined
实际上在这儿运行的代码等同下面的代码:
- var foo;
- console.log(foo)
- foo = function () {
- console.log('I am a function foo')
- }
所以函数表达式也同样有变量提升的效果.
来源: http://www.jianshu.com/p/14a2a71ce396