主要区别
var:变数未宣告前使用,会出现undefinedvar为函式作用域(function scope),不会受限在区块作用域(block scope)内=>区块语句(if、else、 for、 while等)可能会汙染全域变数可以重複宣告let:变数未宣告前使用,会出现Uncaught ReferenceError为区块作用域(block scope)不会产生全域变数无法在同一层 Block 重複宣告变数宣告后能更改值const:变数未宣告前使用,会出现Uncaught ReferenceError常用在一些不能被变更的变数在宣告时变数就必定要指定给值,不然会产生错误。具备 let 所有的特性(唯一不同点是宣告后不能更改值)不过有个例外,就是 { 物件 } 跟 [ 阵列 ] 还是会被变更若不想被修改可以用 Object.freeze() ,冻结一个物件,用于防止物件新增属性,或是防止原有的属性被删除。重要!
如果在作用域内没有宣告,变数就会往外层的作用域找看看有没有宣告,全域都没找到,就会在全域的最开端进行宣告,也就是说如果在作用域里面没有宣告的变数就会变成全域变数。
建议在开发ES6之后的专案中,使用“ const ”或者“let”严谨的宣告变数而非“var”,除了让开发的专案更加稳定外,也可以增加程式码的可读性。
题目
回答出为何出现下列状况:
1.第二个console.log(i)为何为3
for(var i=0; i<3; i++){ console.log(i,"Hi"); // 依次出现 0 "Hi"、1 "Hi"、2 "Hi"}console.log(i);// 出现3
Ans:因var是函式作用域,故汙染全域下的i
2.为何出现错误
let a = 6;let a = 20;console.log(a);//出现错误:Identifier 'a' has already been declared
var a = 6;let a = 20;console.log(a);//出现错误:Identifier 'a' has already been declared
Ans:因let无法在同一层 Block 重複宣告变数(即使另一个是用 var 宣告的变数也不行)
3.为何const能够重新赋值
const myObj = { url: "http://123.com"}myObj.url = "changed";console.log(myObj.url); // changed
Ans:因为在 JS 中阵列和物件都是属于 reference type,在修改时并没有把这个常数指向其他地方,故可更改
console.log(a)个别的值
var a = 5;(function(){ var a = 30 ; console.log(a);})();console.log(a);if(a !== 0 ){ var a = 10;};console.log(a);
第一个console.log(a)--->在立即函式里,为函式作用域,故为30。
第二个console.log(a)--->在全域里,故为5。
第三个console.log(a)--->在区块作用域里,故全域汙染,故为10。
3.必刷热门面试题
function sayHi() { var a = 'Mary'; a = 'Tom';}var a = 'Casper';sayHi();console.log('Hello' + ' ' + a); //"Hello Casper"
function sayHi() { a = 'Tom';}var a = 'Casper';sayHi();console.log('Hello' + ' ' + a); // "Hello Tom"因sayHi()里的a无宣告,故汙染全域变数
多层进阶题function sayHi() { a = 'Tom'; var a = "sam"; function sayho(){ a = "ohmygod" }; sayho();}var a = 'Casper';sayHi();console.log('Hello' + ' ' + a); //Hello Casper
function sayHi() { a = 'Tom'; function sayho(){ a = "ohmygod" }; sayho();}var a = 'Casper';sayHi();console.log('Hello' + ' ' + a); //Hello ohmygod