js 我不知道的東西太特么多了,基礎不扎實,因此這系列是在日常學習中看到的知識點然后自己作不同的嘗試去擴展與填充自己知識空白部分
從 ES6 聲明變量的方式開始
聲明變量這個東西必須用,但真的了解多少?
未聲明變量
當我直接輸出一個未聲明的變量 myname 是會報一個未捕獲的錯誤 Uncaught ReferenceError: myname is not defined
var log = '能夠執(zhí)行到這里?';
console.log(myname); // Uncaught ReferenceError: myname is not defined
console.log(log); // 上行代碼報錯后此行及之后的代碼不會繼續(xù)執(zhí)行

未捕獲的錯誤
捕獲異常
為了不影響后續(xù)代碼執(zhí)行,我們需要用 try catch 來捕獲錯誤,
// var 的變量提升
var log = '能夠執(zhí)行到這里?'
try {
console.log(myname);
alert('不會執(zhí)行') // 上行代碼捕獲到異常后此行代碼也不會執(zhí)行
} catch (e) {
console.log(e); // 日志輸出
console.warn(e); // 警告黃色輸出
console.error(e); // 錯誤紅色輸出
console.table(e); // 表格的方式輸出,包含了錯誤在文件中第幾行第幾列
}
console.log(log); // 能夠執(zhí)行到這里? 由于捕獲了異常所以可以執(zhí)行這行代碼
這里正好用控制臺的 4 個 api 來輸出錯誤信息

控制臺的 4 個 api 來輸出錯誤信息
這里你會看到 try catch 后的兩點變化
- 代碼能繼續(xù)執(zhí)行
-
未捕獲的錯誤
Uncaught ReferenceError已經(jīng)變成ReferenceError
這里有個小插曲,為什么變量要用
myname而不是name,因為 name 是 window 的一個內置屬性,值為空字符串,所以在未聲明 name 的前訪問是不會報錯,但未聲明 myName 則胡報錯
console.log(name); // ''
console.log(myName); // Uncaught ReferenceError: myName is not defined
代碼地址 git repo
commit 5c9642bfdfdc73be20543b8c39bddd58ce308bec
var 聲明變量
- 變量提升
- 可重復聲明并賦值
// var 聲明變量
console.log(log); // var 聲明的變量會變量提升,因此這里不會報錯而是輸出默認值 undefined
var log = '存在'
console.log(log); // 存在
var log = "已成功改變"; // 可重復聲明 var,不會報錯
console.log(log); // 已成功改變
var log; // 不賦值不改變值
console.log(log); // 已成功改變
let 聲明變量
- 變量不會提升
- 不可重復聲明并賦值
// var 聲明變量
console.log(log); // var 聲明的變量會變量提升,因此這里不會報錯而是輸出默認值 undefined
var log = '存在'
console.log(log); // 存在
var log = "已成功改變"; // 可重復聲明 var,不會報錯
console.log(log); // 已成功改變
var log; // 不賦值不改變值
console.log(log); // 已成功改變
// let 聲明變量
console.log(log1); // 不能在用 let 聲明變量前訪問 Uncaught ReferenceError: Cannot access 'log1' before initialization,let 聲明的變量不存在提升
let log1 = 'let 聲明的變量';
let log = '修改 var 變量的值'; // 不可重復聲明 var 或 let 聲明過的變量 Uncaught SyntaxError: Identifier 'log' has already been declared, SyntaxError 會導致整個程序不運行
// 無論是 var 還是 let 聲明過的變量,都不能重復聲明
let log1 = '重新賦值'; // Uncaught SyntaxError: Identifier 'log1' has already been declared
let log = '重新賦值'; // Uncaught SyntaxError: Identifier 'log' has already been declared
進入語法分析時:
- 如果語法錯誤
SyntaxError,則整個程序不會運行; - 如果引用錯誤
ReferenceError,只會導致錯誤后面的代碼無法執(zhí)行;
代碼地址 git repo
commit f75661ecbff1687aa05df88ed06961a22d309d21
作用域
- js 里面只有
全局作用域和函數(shù)作用域,沒有局部作用域 - js 運行會有一個預解析過程,解析后會有一個語法樹,再進入執(zhí)行階段
if (false) {
var log = "能否輸出?"
}
console.log(log); // undefined 這里會有一個預解析(解析后會有一個語法樹,再進入執(zhí)行階段)的過程,var 聲明的變量會在執(zhí)行前將變量提升到作用域上
if (false) {
let log1 = "能否輸出?" // let 聲明的變量只存在離他最近的大括號內
}
console.log(log1); // Uncaught ReferenceError: log1 is not defined,即使是 true log1 這行還是會報錯
- for 循壞
- var 聲明的變量沒有局部作用域,因此控制臺可以輸出最后計算的值
- let 聲明的變量在 for 循環(huán)中使用是存在局部作用域(離他最近的大括號內),因此這里不會覆蓋 var 聲明的 i,也不會出現(xiàn)重復聲明 i
// var 聲明的變量沒有局部作用域,因此控制臺可以輸出最后計算的值
for (var i = 0; i < 3; i++) {}
console.log(i); // 3
// let 聲明的變量在 for 循環(huán)中使用是存在局部作用域(離他最近的大括號內),因此這里不會覆蓋 var 聲明的 i,也不會出現(xiàn)重復聲明 i
for (let i = 0; i < 5; i++) {
console.log(i); // 1, 2, 3, 4, 5,這里輸出的是 let 里的 i
}
console.log(i); // 3 這里輸出的 i 是 var 聲明的 i
- 閉包
- 使用 var 聲明 for 循環(huán)的初始變量 j,最終 j 點擊按鈕的時候會輸出計算后的最終值
- 使用 let 聲明 for 循環(huán)的初始變量 j,由于存在塊級別作用域,會將 j 的值鎖死在當前作用域內,因此點擊會輸出對應的 j 值
// 使用 var 聲明 for 循環(huán)的初始變量 j,最終 j 點擊按鈕的時候會輸出計算后的最終值
for (var j = 0; j < 2; j++) {
document.querySelector('#var').addEventListener('click', () => console.log(j))
}
// var 聲明的也可使用閉包解決沒全局作用域的問題
for (var k = 0; k < 2; k++) {
(function(param){
document.querySelector('#closure').addEventListener('click', () => console.log(param))
})(k)
}
// 使用 let 聲明 for 循環(huán)的初始變量 j,由于存在塊級別作用域,會將 j 的值鎖死在當前作用域內,因此點擊會輸出對應的 j 值
// let 的寫法明顯優(yōu)雅與閉包,但 let 聲明變量性能會稍遜于 var,因為編譯時會自動生成閉包
for (let j = 0; j < 2; j++) {
document.querySelector('#let').addEventListener('click', () => console.log(j))
}
let 的寫法明顯優(yōu)雅與閉包,但 let 聲明變量性能會稍遜于 var,因為編譯時會自動生成閉包
代碼地址 git repo
commit 3e68005f3f08cdc5249be9c1ebeff82e95bf23ea
const 聲明常量
js 一直以來都沒有常量這個概念,es6 加入了常量,讓使用 const 聲明的常量變量不能重新賦值,多用于引入模塊保存到常量
// 常量
const log = '常量會被改變嗎?';
log = '不會'; // Uncaught TypeError: Assignment to constant variable.
console.log(log);
代碼地址 git repo
commit e6dbf861265b7b2901e1acd97fa1fdd1cbdbce2b