最近在Medium上看到一篇关于“变量提高”的文章,原文在此:《A guide to JavaScript variable hoisting with let and const》。为了培养本身看英文文档习惯且看懂的须要,就翻译一下。谈不上精确,欢迎指正。javascript
对于刚入门的JavaScript开发者时常难以理解“变量/方法”提高(hoisting)的独特行为。
接下来咱们要谈论var,let,const声明,那么先了解变量提高就显得更为重要了。那就开始吧。java
JavaScript引擎用“var”处理全部变量声明,无论在哪里声明,最后都会在函数做用域顶端(若是在函数内部声明)或则在全局做用域顶端(在函数外部声明)。这就是“提高”。
所以变量实际上可能在声明它以前就已经被引擎得到了。程序员
在实际操做中看看效果..es6
// OUTPUT : undefined console.log(shape); var shape = square; // OUTPUT : square console.log(shape);
若是你来自C语言,你认为在第一个console.log那里就会抛出变量未定义的错误。但JavaScript解释器预感和“提高”全部变量声明到做用域顶端,而且在那进行初始化。
下面演示实际发生了什么:ide
//declaration getting hoisted at the top var shape; // OUTPUT : undefined console.log(shape); shape = square; // OUTPUT : square console.log(shape);
另外一个例子是用函数做用域来更清楚的展现:函数
function getShape(condition) { // shape exists here with a value of undefined // OUTPUT : undefined console.log(shape); if (condition) { var shape = square; // some other code return shape; } else { // shape exists here with a value of undefined return false; } }
上面的例子能够看出shape声明被提高到了“getShape”函数做用域的顶端。这是由于“if/else” 不能像其余语言那样,建立局部做用域。在JavaScript里,函数做用域实际上就是局部做用域了。所以,“shape”能够在if块以外,函数做用域内任意访问,且值为“undefined”。ui
JavaScript的这个默认行为,既是优势,又是缺点。没有彻底掌握的话,会给咱们的代码带来细微且危险的bugs。spa
ES6 引入了块级做用域,这让开发者对变量有了更多的控制,且让变量有灵活的生命周期。
块级声明在块级/词法做用域里面声明,他们在“{}”中被建立。翻译
“let”语法跟“var”类似,只是用“let”标识符来替换“var”标识符进行变量声明,其做用域范围仅仅在声明的那个代码块。
let声明放在块的顶端,所以只能在那个块级做用域中访问。
举例:3d
function getShape(condition) { // shape doesn't exist here // console.log(shape); ReferenceError: shape is not defined if (condition) { let shape = square; // some other code return shape; } else { // shape doesn't exist here as well return false; } }
注意shape只存在if块中,当在if块外面访问时会抛出一个错误,而不是象咱们以前用var声明那样输出“undefined”。
提示:在同一个做用域内,若是已经使用var标识符声明了变量,同时又用let标识符声明同名变量时会抛出错误。
可是,若是在let声明的变量做用域外,声明同名变量是不会报错的。(这种状况也一样适用于咱们即将谈论的const声明。)
举例:
var shape = square; let shape = rectangle; // SyntaxError: Identifier 'shape' has already been declared
和
var shape = square; if (condition) { // doesn't throw an error let shape = rectangle; // more code } // No error
const声明语法与let和var类似,生命周期与let相同,但你还要注意一些规则。
用const声明的变量将像常量看待,所以它们的值在定义后是不能够修改的。因为这样,每一个const变量都必须在声明的同时进行初始化。
举例:
// valid const shape = triangle; // syntax error: missing initialization const color; // TypeError: Assignment to constant variable shape = square;
然而,这个规则在声明对象时有点不一样。对象属性的值能够被修改!
const shape = { name: triangle, sides: 3 } // WORKS shape.name = square; shape.sides = 4; // SyntaxError: Invalid shorthand property initializer shape = { name: hexagon, sides: 6 }
在上面的例子中,咱们能够看到shape对象属性的值能够被修改,由于咱们只改变shape包含的,而不是它自己。
咱们能够总结说,const能够防止整个绑定的修改,而不是绑定的值。
提示:属性能够改变。因此对于真正不可变的,请使用Immutable.js或Mori。
咱们都知道,若是咱们在使用let,const声明定义的变量以前就使用这些变量,会抛出ReferenceError错误。 在进入做用域和不能访问的这段时间,咱们称为暂时性死区。
提示:“暂时性死区”不是ECMAScript规范里的正式定义,它只是在程序员中广为流行而已。
我我的推荐老是使用const,由于它不容易出错。我还没遇到须要使用var的状况。
做为基本规则,只在循环计数器中,或则你真的须要给变量重新赋值时用let。其余地方,用const。我已经放弃使用循环,转而选择使用filter,map,reduce等方法。你也应该如此。
后记,此做者还有一篇关于方法提高的文章,到时候在搬来。