很长很长一段时间,我们声明一个 JavaScript 变量或常量的方法只有一种,但因为浏览器的实现有关,结果就有了三种方式
var name = 'yufei'; // 1. 官方正统,使用 var 关键字 window.sex = 'male` ; // 2. 特定于浏览器实现。 age = 30; // 3. 浏览器默认存在的功能,此方法相当于 window.age;
如果你经常写 JavaScript,那么一定会碰到很多问题,也一定会收到很多高手的警告,比如
age=30
不管出现在哪里,都相当于在全局作用域下 ( window 作用域下 ) 声明了一个全局的变量,相当于 window.age=30
如果你在函数中使用 var name = 'yufei';
就一定碰到过提权。就是所有的 var
的声明都会自动提到函数的入口处。
饱受痛苦的这么,然后,ECMAScript 2016 中终于带来了两个新的关键字 let
和 const
,前者用于声明不可变变量,后者用于声明常量。
let 关键字
let
关键字的用法非常类似于 var
,但与 var
不同的是,let
声明的变量是块级作用域 ( block scoped ) ,只会存在于当前块中,而 var
声明的变量作用域是函数级别的 ( function scoped )
所谓的块级作用域,就是该变量只在从声明点开始的当前的块 {}
及所有子块 {}
中有效,超出了范围则无效,同时在内部声明的匿名函数中有效
范例: 块级作用域
例如下面的代码
{ let name = 'yufei'; } console.log(name);
运行结果为 undefined
因为输出语句在当前声明的块的外部,所以显示未定义
范例 2 : 子块级作用域
又如下面的代码
{ let name = 'yufei'; { console.log('in child block:',name); } console.log('in same block:', name); }
输出结果如下
in child block: yufei in same block: yufei
因为块级的作用域也包括子块级作用域
范例 3 : 内部函数
我们再来看看下面的代码,在当前作用域内声明了一个内部函数
{ let name = 'yufei'; { (function () { console.log('in internal function:',name); })(); } function hello() { console.log('Hello:' + name); } hello(); }
输出结果如下
in internal function: yufei VM69:10 Hello:yufei
块级作用域和函数级作用域
大家都知道,var
关键字声明的作用域是函数级别的,也就是 JavaScript 引擎会把一个函数中的所有块 ( 非另一个函数 ) 的 var
声明统统收纳到最近的函数的头部
例如下面的代码
function order(x, y) { if (x > y) { // (A) var tmp = x; x = y; y = tmp; } console.log(tmp===x); // 可行,而且还会正常输出 return [x, y]; } order(4,3);
输出结果为 false
,返回结果为 [3, 4]
但如果我们把 var
换成 let
就会报错了
function order(x, y) { if (x > y) { // (A) let tmp = x; x = y; y = tmp; } console.log(tmp===x); // 不可行,提示 tmp 未声明 return [x, y]; } order(4,3);
报错结果如下
Uncaught ReferenceError: tmp is not defined
所以,如果要代码严谨,如果想再大型的项目中,请使用 let
代替 var
吧。