一、存在变量提高,实际上var不管在哪里声明,都会被当作当前的做用域顶部声明变量。 二、能够重复声明,后声明的变量会覆盖前声明的变量。
一、不存在变量提高。 二、禁止重复声明。 三、块级做用域,只在当前做用域块有用。 四、临时死区,并且不能在声明以前访问它。
一、const 声明的是常量,其值一旦肯定后不能够修改 二、const 声明常量时候必需要进行赋值 三、const 不存在变量提高,一旦执行快外就会当即销毁。 四、const 只能在当前代码块级有效, 五、const 不能重复声明相同常量。 六、const声明不容许修改绑定,但容许修改值,也就是说用const建立对象后,能够修改该对象的属性值。
每种编程语言都有变量,声明变量的方法各不一样,在JavaScript里面,最经典的var声明一个变量,当ECMAScript6出现后,新增了2个声明变量的方法:let和const,那什么时候建立变量,用什么声明变量方法会更好呢?编程
var声明一个变量时候,只须要 var name; 或者声明赋值var name = "Bob";闭包
实际上var不管在哪里声明,都会被当作当前的做用域顶部声明变量。编程语言
// var 的变量提高机制 function getValue(condition) { if (condition) { var values = 'Bob'; return values; } else { console.log(values); // 这里访问到values 是undefined,缘由下面解释: return null; } } // 缘由解释:为何上面的代码else还能访问values的值,虽然是undefined // 不管变量values都会被建立,在编译过程当中,JavaScript引擎会将上面的getValue函数修改为这样: function getValue(condition) { // 重点看这里,变量values的声明被提高到函数顶部 var values; if (condition) { values = 'Bob'; return values; } else { console.log(values); // 因此这里访问到是声明过的但未赋值的values,因此是undefined。 return null; } }
块级声明用于声明在指定的块的做用域以外没法访问的变量函数
let声明变量和var声明变量,但let有本身的四个特征:code
咱们能够把刚才聊到的getValue函数修改一下:对象
// let 块级做用域 && 不存在变量提高 function getValue(condition) { if (condition) { // 使用let声明变量 let values = 'Bob'; return values; } else { console.log(values); // 这里报错: ReferenceError: values is not defined.. // 缘由就是用let声明的变量,是不存在变量提高的, // 并且values变量只能在if{ 这个做用块里面有效 } 外面是访问不到的 // 同时,在外面访问不只会访问不到,并且会报错 return null; } } // let 禁止重复声明相同变量 function getValue() { var values = "Bob"; let values = {name: 'Bob'}; // 使用let声明变量禁止重复声明已经有的变量名 // 不然报错:SyntaxError: Identifier 'values' has already been declared }
function getValue() { // 声明一个常量 const USER_NAME = "梁凤波"; // 禁止重复声明相同常量,不然报错:TypeError: Assignment to constant variable. // const USER_NAME = "Bob"; // 记住:const声明不容许修改绑定,但容许修改值, // 也就是说用const建立对象后,能够修改该对象的属性值 const STUDYENT = { name: '梁凤波' }; console.log(`STUDYENT.name = ${STUDYENT.name}`); // STUDYENT.name = 梁凤波 STUDYENT.name = 'Bob'; console.log(`STUDYENT.name = ${STUDYENT.name}`); // STUDYENT.name = Bob }
// 在for循环内用var 声明,在外面访问到的是for循环后的结果 for (var i = 0; i < 10; i++) { } console.log(`i = ${i}`); // i = 10 // 在for循环内用let 声明,在外面 访问不到,块级做用域问题 for (let i = 0; i < 10; i++) { } console.log(`i = ${i}`); // ReferenceError: i is not defined
// 通过for循环后,在外面访问i,是直接访问到告终果i = 10 let funcs = []; for (var i = 0; i < 10; i++) { funcs.push(function () { console.log(i); }) } funcs.forEach(func => { func() // 分别输出10次10 });
缘由:循环里每次迭代同时共享着变量i,循环内部建立的函数全保留相同变量的引用,循环结束时候i的值变为10,因此每次调用console.log(i)时候回输出数字10ip
为了解决这个问题,能够在循环中使用当即调用函数表达式(IIFE),以强制生成计数器变量的副本:作用域
// 若是要理想效果,在外面分别输出 0 ~ 9, // 可使用闭包暴露出去 let funcs = []; for (var i = 0; i < 10; i++) { funcs.push((function (val) { return function () { console.log(val); } }(i))) } funcs.forEach(func => { func() });
let funcs = []; for (let i = 0; i < 10; i++) { funcs.push(function () { console.log(i); }) } funcs.forEach(func => { func() // 分别输出 0 ~ 9 });
let 声明模仿上述示例IIFE所作的一切简化循环过程,每次迭代循环都会建立一个新变量,并以以前迭代中同名变量的值将其初始化。get
let funcs = []; let obj = { a: true, b: true, c: true } for (const key in obj) { funcs.push(function () { console.log(key); }) } funcs.forEach(func => { func() // 分别输出 a, b, c Authorization });
let和const声明循环,const循环是不能改变key的值,const 循环应该使用for-in,for-of,其余和let示例同样,由于每次迭代不会像var循环例子同样修改已有的绑定,而是会建立一个新绑定。it
var RegExp = "Bob"; // 即便是全局对象RegExp定义在window,也不能幸免被var声明覆盖 console.log(RegExp); // Bob console.log(window.RegExp); // Bob let RegExp = "Bob"; // 用let或const声明不能覆盖全局变量,而只能屏蔽它 console.log(RegExp); // Bob console.log(window.RegExp); // undefined console.log(window.RegExp === RegExp); // false const ncz = 'Hi!' console.log('ncz' in window); // false
默认使用const,只在确实需求改变变量的值使用let,这样就能够在某种程度上实现代码的不可变,从而防止默写错误产生。