欢迎访问我的站点javascript
做用域指变量所做用的范围,在 Javascript 中有两种做用域:java
变量提高(Hoisting)被认为是, Javascript 中执行上下文 (特别是建立和执行阶段)工做方式的一种认识。具体表现就是全部经过 var 声明的变量会提高到当前做用域的最前面。安全
function foo() {
console.log(temp);
}
function bar() {
console.log(temp);
var temp;
}
foo(); // ReferenceError: temp is not defined
bar(); // undefined
复制代码
能够看到用 var 声明了的并不会报错。由于其实函数 bar 等同于微信
function bar() {
var temp;
console.log(temp);
}
复制代码
大多数类 C 语言语法的语言都拥有块级做用域。在一个代码块(括在一对花括号中的一组语句)中定义的全部变量在代码块的外部是不可见的。定义在代码块中的变量在代码块被执行结束后会变释放掉。这是件好事。函数
糟糕的是,尽管 Javascript 的代码貌似支持块级做用域,但实际上 Javascript 并不支持(就是由于有变量提高)。这个混淆之处可能成为错误之源。ui
因此在 ES6 中规定了 let 和 const 来支持块级做用域。可是,是否是真的提高就不存在了呢,能够看下面暂时性死区这部分。spa
let 能够理解为『更完美的 var』,使用方法很简单;指针
let foo = 3;
复制代码
使用方法基本和 var 相同,并且声明的变量只在其块和子块中可用,这点也与 var 相同。 两者之间最主要的区别在于 var 声明的变量的做用域是整个封闭函数。code
function foo() {
if(true) {
var temp = 5;
console.log(temp);
}
console.log(temp);
}
function bar() { if(true) {
let temp = 5;
console.log(temp);
}
console.log(temp);
}
foo(); // 5 和 5
bar(); // 5 和 "ReferenceError: temp is not defined
复制代码
let 声明的变量的做用域只是外层块,而不是整个外层函数。cdn
咱们能够利用这个特性来替代当即执行函数(IIFE)。
// IIFE
(function(){
var temp = xxx;
/* other code */
}())
// 块级
{
let temp = xxx;
/* other code */
}
复制代码
const 的用法跟 let 差很少,可是 const 必定要初始化, 不初始化是会报错的。
const temp = 4;
// 没有初始化报错
const t; // SyntaxError: Missing initializer in const declaration
复制代码
const 是块级做用域,const 跟 let 的语义类似,就是用来声明常量的,一旦声明了就不能更改。值得注意的是 const 声明的变量记录的是指针,不可更改的是指针,若是 const 所声明的是对象,对象的内容仍是能够修改的。
// 从新赋值声明致使报错
const PI = 3.14;
PI = 3.1415926; // TypeError: Assignment to constant variable.
// 给对象增长属性不会致使 obj 的指针变化,因此不会报错
const obj = { foo: 2 };
obj.bar = 3;
console.log(obj); // {foo: 2, bar: 3}
复制代码
使用 let 或 const 声明的变量,在声明没有到达以前,访问该变量都会致使报错,就连一直觉得安全的 typeof 也再也不安全。
// TDZ1
function foo() {
// TDZ 开始
console.log(typeof temp);
let temp = 5; // TDZ 结束
}
foo(); // ReferenceError: temp is not defined
复制代码
报的错是 ReferenceError,若是使用 var 声明的话,temp 输出应该是 undefined,从 let 声明的变量的块的第一行,到声明变量之间的这个区域被称做暂时性死区(TDZ)。凡是在这个区域使用这些变量都会报错。
// TDZ2
function bar() {
console.log(typeof temp);
}
bar(); // undefined
复制代码
看到上面两个例子仔细思考有没有以为想到点什么?
在函数里没有用 let 声明 temp 的时候,temp 是 undefined,讲道理在 let 声明前也应该是 temp,然而 foo 函数却报了错,证实了就算是在未到达 let 声明的地方,可是在用 let 以前已经起到了做用。这是否是说明其实 let 也有提高(这个提高并非 var 的那种提高,只是有影响),只是在 TDZ 使用的时候报错了,而不是 undefined。
事实上,当 JS 引擎检视下面的代码块有变量声明时,对于 var 声明的变量,会将声明提高到函数或全局做用域的顶部,而对 let 或 const 的时候会将声明放在暂时性死区内。任何在暂时性死区内访问变量的企图都会致使“运行时”错误(runtime error)。只有执行到变量的声明语句时,该变量才会从暂时性死区内被移除并能够安全使用。
在同一个块内,let 和 const 不能声明相同的标识符。禁止的状况包括:
// let 和 let
let foo = 1;
let foo = 2;
// let 和 const
let foo = 1;
const foo = 2;
// var 与 let
var foo = 1;
let foo = 2;
// 函数参数与 let
function bar(foo) {
let foo = 1;
}
复制代码
以上状况都是会报 SyntaxError。可是在嵌套的做用域内使用 let 声明同一变量是被容许的。
var foo = 1;
{
// 不会报错
let = 2;
// other code
}
复制代码
同时由于是 let 和 const 是块级做用域,声明的变量在当前块使用完以后就会被释放,因此就算使用相同的标识符也不会覆盖外部做用域的变量, 而 var 是会覆盖外部做用域的变量的。
function foo() {
var bar = 1;
{
let bar = 2;
}
console.log(bar);
}
function zoo() {
var bar = 1;
{
var bar = 2;
}
console.log(bar);
}
foo(); // 1
zoo(); // 2
复制代码
在 ES6 的发展阶段,被普遍承认的变量声明方式是:默认状况下应当使用 let 而不是 var 。对于多数 JS 开发者来讲, let 的行为方式正是 var 本应有的方式,所以直接用 let 替代 var 更符合逻辑。在这种状况下,你应当对须要受到保护的变量使用 const 。
在默认状况下使用 const ,而只在你知道变量值须要被更改的状况下才使用 let 。这在代码中能确保基本层次的不可变性,有助于防止某些类型的错误。
两个思考题,能够在评论里面回答,我后面会把个人想法放在评论中。
// 思考题 1
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // TypeError for redeclaration.
break;
}
// 思考题 2
function bar(){
var foo = 1;
if (true) {
let foo = (foo + 2);
}
}
bar();
复制代码
你们好,我是桃翁,我为本身代言!
我的微信公众号