錯誤處理機制
1、Error 實例對象
js所有拋出的錯誤都是Error構(gòu)造函數(shù)的實例,參數(shù)表示錯誤提示,可以從實例的message屬性讀到
var err = new Error('出錯了');
err.message // "出錯了"
- 拋出
Error實例,執(zhí)行中斷
整個程序就中斷在發(fā)生錯誤的地方,不再執(zhí)行后面代碼
-
屬性
- message:錯誤提示信息
- name:錯誤名稱(非標準屬性)
- stack:查看錯誤發(fā)生時的堆棧(非標準屬性)
function throwit() {
throw new Error('');//拋出
}
function catchit() {
try {
throwit();
} catch(e) {
console.log(e.stack); // print stack trace
}
}
catchit()
// Error
// at throwit (~/examples/throwcatch.js:9:11)
// at catchit (~/examples/throwcatch.js:3:9)
// at repl:1:5
錯誤堆棧的最內(nèi)層是throwit函數(shù),然后是catchit函數(shù),最后是函數(shù)的運行環(huán)境
2、自定義錯誤
function UserError(message) {
this.message = message || '默認信息';
this.name = 'UserError';
}
//自定義錯誤對象
throw new UserError('出錯了!');
3、throw語句
用來手動中斷程序執(zhí)行,拋出一個錯誤
實際上,throw可以拋出任何類型的值
-
錯誤對象
function UserError(message) { this.message = message || '默認信息'; this.name = 'UserError'; } //自定義錯誤對象 throw new UserError('出錯了!'); -
其他類型
// 拋出一個字符串 throw 'Error!'; // Uncaught Error! // 拋出一個數(shù)值 throw 42; // Uncaught 42 // 拋出一個布爾值 throw true; // Uncaught true // 拋出一個對象 throw { toString: function () { return 'Error!'; } }; // Uncaught {toString: ?}
4、try...catch語句
允許對錯誤進行處理,選擇是否往下執(zhí)行
try {
throw "出錯了";
} catch (e) {
console.log(111);
}
console.log(222);
// 111
// 222
- 不中斷
catch代碼塊捕獲try中拋出的錯誤之后,程序不會中斷(除非return),會繼續(xù)執(zhí)行下去
- 可嵌套
可以嵌套使用try...catch結(jié)構(gòu)
5、finally代碼塊
在try...catch最后添加finally,不管是否出現(xiàn)錯誤,最后必需運行的語句
-
錯誤沒有捕獲,中斷
沒有
catch捕獲錯誤,執(zhí)行finally后,程序就中斷在錯誤拋出的地方
try {
throw new Error('出錯了……');
console.log('此行不會執(zhí)行');
} finally {
console.log('完成清理工作');
}
// 完成清理工作
// Error: 出錯了……
-
try / catch 有return
try中return,延遲到finally執(zhí)行完再返回
var count = 0; function countUp() { try { return count; } finally { count++; } } countUp() // 0 count // 1try中throw,catch也有return,在catch中return時,跳到finally執(zhí)行(如果finally沒return,會等finally執(zhí)行完,再執(zhí)行catch中return;如果return,則不會執(zhí)行catch中的return語句
try{}catch{}finally{}中存在return,則該結(jié)構(gòu)后面的語句不執(zhí)行
function f() { try { console.log(0); throw 'bug'; } catch(e) { console.log(1); return true; // 這句原本會延遲到 finally 代碼塊結(jié)束再執(zhí)行 console.log(2); // 不會運行 } finally { console.log(3); return false; // 這句會覆蓋掉前面那句 return console.log(4); // 不會運行 } console.log(5); // 不會運行 } var result = f(); // 0 // 1 // 3 result // false -
try / catch 有throw
try中throw,之后語句不執(zhí)行,跳到catch執(zhí)行
try中throw,catch也有throw,在catch中throw時,跳到finally執(zhí)行(如果finally沒return,會等finally執(zhí)行完,再執(zhí)行catch中throw;如果return,則不會執(zhí)行catch中的throw語句
function f() { try { throw '出錯了!'; } catch(e) { console.log('捕捉到內(nèi)部錯誤'); throw e; // 這句原本會等到finally結(jié)束再執(zhí)行 } finally { return false; // 直接返回 } } try { f(); } catch(e) { // 此處不會執(zhí)行 console.log('caught outer "bogus"'); } // 捕捉到內(nèi)部錯誤
類型轉(zhuǎn)換
強制轉(zhuǎn)換
1、Number()
-
簡單數(shù)據(jù)類型
// 數(shù)字 -> 數(shù)字 Number(324) // 324 /* 字符串 -> 1.全是數(shù)字:對應(yīng)數(shù)字 2.空串:0 3.含字母其他:NaN -----> Number將字符串轉(zhuǎn)為數(shù)值,比parseInt函數(shù)嚴格,只要有一個字符無法轉(zhuǎn)成數(shù)值,整個字符串就會被轉(zhuǎn)為NaN */ parseInt('42 cats') // 42 Number('42 cats') // NaN //布爾 -> true為1,false為0 //null -> 0 //undefined -> NaN -
對象類型
除了包含單個數(shù)值的數(shù)組,其他都是NaN
Number({a: 1}) // NaN Number([1, 2, 3]) // NaN Number([5]) // 5Number背后的轉(zhuǎn)換規(guī)則比較復(fù)雜:1、調(diào)用對象的
valueOf方法返回的簡單數(shù)據(jù)類型,直接對返回結(jié)果使用Number(),結(jié)束
2、調(diào)用對象的
toString方法1中返回的是對象時,調(diào)用toString
返回的簡單數(shù)據(jù)類型,直接對返回結(jié)果使用Number(),結(jié)束
3、報錯
2中
toString方法返回的是對象,就報錯
2、String()
-
簡單數(shù)據(jù)類型
- 數(shù)值:轉(zhuǎn)為相應(yīng)的字符串
- 字符串:原來的值
-
布爾值:
"true","false" -
undefined:
"undefined" -
null:
"null"
-
對象類型
- 對象,返回一個類型字符串
- 數(shù)組,返回該數(shù)組的字符串形式
String({a: 1}) // "[object Object]" String([1, 2, 3]) // "1,2,3"String()轉(zhuǎn)換規(guī)則與
Number方法基本相同,只是互換了valueOf方法和toString方法的執(zhí)行順序String({a: 1}) // "[object Object]" // 等同于 String({a: 1}.toString()) // "[object Object]"
3、Boolean()
-
false五種情況
除了以下五個轉(zhuǎn)換為false,其余為true
undefined
null
-
-0 或 +0
Boolean(0) // false NaN
' '(空字符串)
-
對象都是true,
false對應(yīng)的布爾對象也是Boolean({}) // true Boolean([]) // true Boolean(new Boolean(false)) // true
自動轉(zhuǎn)換
1、布爾值
預(yù)期為布爾值的地方(比如if語句的條件部分),會自動轉(zhuǎn)換為布爾值
將一個表達式轉(zhuǎn)為布爾值
// 寫法一
expression ? true : false
// 寫法二
!! expression
2、字符串
字符串的加法運算,一個值為字符串,一個非字符串
具體規(guī)則是,先將復(fù)合類型的值轉(zhuǎn)為原始類型的值,再將原始類型的值轉(zhuǎn)為字符串
'5' + {} // "5[object Object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"
3、數(shù)值
- 其他運算符(除了+)
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN
-
一元運算符
一元運算符也會把運算子轉(zhuǎn)成數(shù)值
+'abc' // NaN
-'abc' // NaN
+true // 1
-false // 0
set數(shù)據(jù)結(jié)構(gòu)
//
// 1.接收一個數(shù)組參數(shù), 將數(shù)組去重再保存
// 2.set.clear()清空set 無返回值 返回undefined
// 3.set.add(val)添加某個值,返回set對象本身{1,2,3,4,5}
// 4.set.delete(val)刪除某個值,返回是否刪除成功
// 5.set.has(val)查找某個值,返回是否包含
// 6.set.size屬性 值的個數(shù)
// 數(shù)組的去重
let arr = [1,2,3,4,5,1,2];
let set = new Set(arr);
arr = [...set];
map數(shù)據(jù)結(jié)構(gòu)
// map數(shù)據(jù)結(jié)構(gòu) :類似于對象
// 1.接收一個二維數(shù)組,將數(shù)組轉(zhuǎn)化成key-value的形式
// 2.map.clear()清空 map變?yōu)閧}
// 3.map.get(key)獲取key對應(yīng)的value值
// 4.map.has(key) 返回是否包含
// 5.map.set(key,val)修改或增加key
// 6.map.delete(key) 返回是否刪除成功
// 7.map.size屬性 值的個數(shù)
let arr=[
['a',1],
['a2',2],
['a3',3]
]
let map = new Map(arr);
console.log(map);
// {'a'=>1,'a'=>2,'a'=>3}
數(shù)組鍵名
1、數(shù)組的鍵名可以是整數(shù)或字符串?
arr = [1,2,3];
arr[0] //1
arr['0'] //1
arr.0//報錯
之所以可以用數(shù)值讀取,是因為非字符串的鍵名會被轉(zhuǎn)為字符串
(方括號是運算符,可以接受數(shù)值,點結(jié)構(gòu)不能)
2、數(shù)組的本質(zhì)
是個對象
arr = [];
typeof arr;//object
3、length屬性是可寫的
可用來清空數(shù)組,將length屬性設(shè)為0
var arr = [ 'a', 'b', 'c' ];
arr.length = 0;
arr // []
人為設(shè)置length大于當前元素個數(shù),會自動新增,新增位置為空
var a = ['a'];
a.length = 3;
a[1] // undefined
小于,則會自動刪除多余元素
注意:使用delete命令刪除數(shù)組元素,會形成空位,length不變
類似數(shù)組的對象
一個對象的所有鍵名都是正整數(shù)或零,并有length屬性,這個對象就很像數(shù)組,但不是數(shù)組。
1、和數(shù)組的區(qū)別
- 他沒有數(shù)組特有的方法,且length為靜態(tài),不隨元素變化而變化
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function
2、有哪些例子
以下例子可以:使用[ ]獲取元素,用length獲取長度,但instanceof Array為false
- 函數(shù)的不定參數(shù)arguments
- DOM元素集
- 字符串
3、轉(zhuǎn)換為真正數(shù)組
有以下幾種方法:
-
使用數(shù)組方法slice,轉(zhuǎn)換為真正數(shù)組
var arr = Array.prototype.slice.call(arguments); arr.forEach((element, index) => { }) -
使用call調(diào)用數(shù)組方法
Array.prototype.forEach.call(arguments, (element, index) => { //等同于調(diào)用for循環(huán) })但是,真正轉(zhuǎn)為數(shù)組,再使用數(shù)組方法要比后面的方法快
對象
obj = {
age: 18,
name: "ccc"
}
var a = "sex";
obj[a] = "female";//name: "female"
obj.a = "female";//a: "female"
(方括號是運算符,可以接受變量,點結(jié)構(gòu)不能)
函數(shù)新增方法
// 函數(shù)新增方法
// 箭頭函數(shù)
// 1.箭頭函數(shù)使用()=>返回值,可以直接接收返回值,不用return
// 2.箭頭函數(shù)沒有不定參數(shù)arguments,可以使用(...arg)剩余參數(shù)接收多個參數(shù),組成一個數(shù)組來獲取參數(shù)
// 3.箭頭函數(shù)沒有this 調(diào)用箭頭函數(shù)的this,指向聲明時的作用域的this
數(shù)組新增方法
// 數(shù)組新增方法
// 1.flat(depth) 參數(shù)為遞歸層數(shù),不改變原數(shù)組
let arr = [1,[2,3,[4],5],6];
let arr2 = arr.flat(Infinity);
console.log(arr2);
// 2.flatMap(callback) 只能遞歸一層,返回新組成的數(shù)組
let arr = [['a1',['11','11']],['a2','15']];
let arr2 = arr.flatMap((item, index) => {
console.log(item,index);
// 這里return item相當于flat遞歸一層,將第一層元素為數(shù)組的轉(zhuǎn)為元素
item = item.filter((item,index) => {
return index == 0;
})
return item;
})
console.log(arr2);
// 3.find(callback)返回第一個滿足要求的值 都沒有就是undefined
let arr = [1,2,3,4,5,1,2];
let val = arr.find((item,index)=>{
if(item>3){
return true;
}
});
// 或者
val = arr.find(item => item > 2);
console.log(val);
// 4.findIndex(callback)
let i = arr.findIndex(item => item > 2);
對象新增的方法
// 對象新增的方法
// 1.簡潔表示法
// 1.1屬性簡潔表示
// 1.2方法簡潔表示
// 2.屬性名表達式[]
let age = 10;
let name = 'ccc';
let a = 'sex';
let person = {
name,
age,
[a]: 'man',
say(){
console('say:function() => say(){}');
}
}
console.log(person);
// 對象合并
let obj = {a:1,b:2};
let obj2 = {c:3,d:4};
obj2 = Object.assign(obj2, obj);
console.log(obj2);
let obj2 = {
...obj,
c: 3,
d: 4
};
console.log(obj3);
//is()對象比較
// 1.和===大部分相同,例如以下都是true
// 兩個值都是undefined
// 兩個值都是null
// 兩個值都是true或者false
// 兩個值都是相同字符串
// 兩個值都是同一個對象(地址相同)
// 兩個值都是數(shù)字
// 2.區(qū)別:
// +0 -0
// NaN NaN
console.log(Object.is(+0,-0))//false
console.log(+0 === -0)//true
console.log(NaN === NaN)//false
console.log(Object.is(NaN,NaN))//true
var與let
區(qū)別:塊級作用域
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
-
var命令聲明的,在全局范圍內(nèi)都有效,因此全局只有一個i,所有數(shù)組成員的函數(shù)內(nèi)部的i,指向的都是同一個i,每一次循環(huán),i值改變,最后為10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
-
let聲明的,只在本輪循環(huán)有效,每一次循環(huán)i是一個新的變量,JavaScript 引擎內(nèi)部會記住上一輪循環(huán)的值,在此基礎(chǔ)上進行計算新的i
for循環(huán)作用域
循環(huán)變量的那部分是一個父作用域,而循環(huán)體內(nèi)部是一個單獨的子作用域
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
//說明各自單獨的作用域
Babel的使用
<!-- babel -->
<!-- 一個js的編譯器,可以把es6里面的語法糖轉(zhuǎn)換為瀏覽器可以識別的js語法 -->
<!-- 具體的使用 -->
<!-- 1.引入babel文件 -->
<script src = "js/babel.min.js"> </script>
<script type = "text/babel">
let obj = {a:1};
let obj2 = {
c:3,
...obj,
c(){
console.log("babel編譯器 看瀏覽器代碼是否變了");
}
}
</script>