JavaScript变量提升
JavaScript变量提升(转)
原文 :http://rainsoft.io/javascript-hoisting-in-details/?utm_source=javascriptweekly&utm_medium=email
1、简介
提升是一种将变量和函数的声明移到函数作用域(如果不存在任何函数内的话就是全局作用域)最顶部的机制。
提升影响了变量的生命周期,一个变量的生命周期包含3个阶段:
声明 -> 初始化 -> 使用
一个例子:
1
2
3
4
5
6// 声明
var myValue;
// 初始化
myValue = 100;
// 使用
alert(myValue);
在JavaScript中,函数可以先声明,后使用。初始化被忽略了。一个例子:
1 | // 声明 |
函数的使用可以在声明之前,例如:
1 | // 使用 |
这是因为JavaScript中的函数声明会被提升到作用域的顶部。
变量提升在不同的方面的影响不同:
- 变量声明:var, let或const关键字
- 函数声明: function () {…}
- 类声明:class关键字
以下分开说明三个的区别:
2、函数作用域变量:var
var声明
在函数作用域内创建并初始化一个变量,声明但是未初始化的变量值是undefined。
1 | // 声明变量num |
提升与var
使用var 声明变量会被提升到所在作用域的顶部。如果在声明之前访问该变量,它的值是undefined
。
1 | function double(num) { |
上面的代码在相当于:
1 | function double(num) { |
声明会提升,赋值留在原地
1 | function sum(a, b) { |
声明会被提升,而赋值操作不受影响
上面的代码在相当于:
1 | function sum(a, b) { |
3、块级作用域变量: let
let声明
在块级作用域内,默认情况下,声明但未初始化的变量的值是undefined
。
lets是ECMAScript 6的改进,它允许代码在块的级别是保持模块性和封装性:
1 | if(true) { |
提升与let
使用let定义的变量会被提升到代码块的顶部。但是如果在声明前访问该变量,JavaScript会抛出异常ReferenceError:is not defined。
在声明语句一直到代码库的顶部,变量好像在一个临时死亡区间中一样。例如:
1 | function isTruthy(value) { |
从let myVariable一行一直到此块级的顶部,都是myVariable变量的临时死亡区间。如果在此区间访问该变量,JavaScript会抛出ReferenceError
异常。
那么myVariable是否被提升了?
如果let定义的变量没有被提升,那么在临时死亡区间内myVariable的值就会是’Value 1’。由此我们可以确定块级变量确实有提升。
let 先声明,后使用
1 | if(true) { |
4、常量 const
常量声明
,当声明一个常量时,必须在同一语句中对该变量进行初始化。在声明与初始化之后,变量的值不能被修改。
1 | const PI = 3.14; |
提升与let
使用const定义的常量会被提升到代码块的顶部。
const声明常量提升效果与let什么变量相同。
1 | function double(number) { |
常量始终要先声明初始化之后再使用。
5、function(函数)声明
函数声明
的一个例子:
1 | function isOdd(number) { |
需要注意的function(){…}和函数表达式var x = function(){…}的区别,两者都用于创建函数,但是提升机制不同。
1 | addition(4 ,7); // 11 |
还是var提升中的问题:声明会被提升,而赋值操作不受影响
6、class(类)声明
类声明
使用提供的名称和参数创建一个构造函数。类是ECMAScript 6引入的。
类建立在JavaScript的原型继承之上并提供了方法如:super(访问父类) static(定义静态方法) extends(定义子类)
1 | class Point { |
提升与class
class的提升与let定义变量的提升效果相同
1 | // Throws ReferenceError: Company is not defined |
使用类声明表达式
创建类
1 | console.log(typeof Square); // undefined |
7、总结
JavaScript的提升有多种形式,应该养成好习惯,按照声明->初始化->使用的顺序使用变量