声明语法
var upperA = 'A'; let upperB = 'B'; const upperC = 'C';
只声明不初始化的结果,【 const定义的常量不能够修改,并且必须初始化。】
// var 声明变量 var upperA; console.log('打印大写的A:%s', upperA); // 结果:打印大写的A:undefined // let 声明变量 var upperB; console.log('打印大写的B:%s', upperB); // 结果:打印大写的B:undefined // const 声明常量 const upperC; console.log('打印大写的C:%s', upperC); // 错误:SyntaxError: Missing initializer in const declaration
声明后值是否可修改,【 const定义的常量不能够修改,并且必须初始化。】
// var 声明变量初始化并修改值 var upperA = 'A'; console.log('打印upperA:%s', upperA); // 结果:打印upperA:A upperA = 'LetterA'; console.log('打印upperA:%s', upperA); // 结果:打印upperA:LetterA // let 声明变量初始化并修改值 var upperB = 'B'; console.log('打印大写的B:%s', upperB); // 结果:打印upperB:B upperB = 'LetterB'; console.log('打印大写的B:%s', upperB); // 结果:打印upperB:LetterB // const 声明常量初始化并修改值 const upperC = 'C'; console.log('打印upperC:%s', upperC); // 结果:打印upperC:C upperC = 'LetterC'; console.log('打印upperC:%s', upperC); // 错误:TypeError: Assignment to constant variable.
浏览器在运行代码以前会进行预解析,首先解析函数声明,定义变量,解析完以后再对函数、变量进行运行、赋值等
不论var声明的变量处于当前做用域的第几行,都会提高到做用域的头部。
var 声明的变量会被提高到做用域的顶部并初始化为undefined,而let声明的变量不会被提高到做用域的顶部。
console.log('打印upperA:%s', upperA); // 结果:打印upperA:undefined console.log('打印upperB:%s', upperB); // 错误:ReferenceError: upperB is not defined var upperA = 'A'; let upperB = 'B';
** var容许在相同做用域内,重复声明同一个变量,后面声明的变量会覆盖前面声明的变量。
** let不容许在相同做用域内,重复声明同一个变量。
var upperA = 'A'; let upperB = 'B'; // 重复声明 var upperA = 'LetterA'; let upperB = 'LetterB'; console.log('打印upperA:%s', upperA); console.log('打印upperB:%s', upperB) // 错误:SyntaxError: Identifier 'upperB' has already been declared
在ES6以前,咱们都是用var来声明变量,并且JS只有函数做用域和全局做用域,没有块级做用域,因此{}限定不了var声明变量的访问范围。
// ---------- 例如: ---------- { var upperA = 'A'; } console.log('打印upperA:%s', upperA); # 结果: 打印upperA:A // ---------- ES6新增的let,能够声明块级做用域的变量。---------- { let upperB = 'B'; } console.log('打印upperB:%s', upperB); // 错误: ReferenceError: upperB is not defined
let很是适合用于 for循环内部的块级做用域。
** JS中的for循环体比较特殊,每次执行都是一个全新的独立的块做用域,用let声明的变量传入到 for循环体的做用域后,不会发生改变,不受外界的影响。
// ---------- 看一个常见的面试题目: ---------- for (var i = 0; i <10; i++) { setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。 console.log(i); // 执行此代码时,同步代码for循环已经执行完成 }, 0); } // 输出结果:10 共10个 // 这里面的知识点: JS的事件循环机制,setTimeout的机制等 // ---------- 若是把 var改为 let声明:---------- // i虽然在全局做用域声明,可是在for循环体局部做用域中使用的时候,变量会被固定,不受外界干扰。 for (let i = 0; i < 10; i++) { setTimeout(function() { console.log(i); // i 是循环体内局部做用域,不受外界影响。 }, 0); } // 输出结果:0 1 2 3 4 5 6 7 8 9