數(shù)據(jù)類型的轉(zhuǎn)換
JavaScript 是一種動(dòng)態(tài)類型語(yǔ)言,變量沒(méi)有類型限制,可以隨時(shí)賦予任意值。
var x = y ? 1 : 'a';
上面代碼中,變量x到底是數(shù)值還是字符串,取決于另一個(gè)變量y的值。y為true時(shí),x是一個(gè)數(shù)值;y為false時(shí),x是一個(gè)字符串。這意味著,x的類型沒(méi)法在編譯階段就知道,必須等到運(yùn)行時(shí)才能知道。
雖然變量的數(shù)據(jù)類型是不確定的,但是各種運(yùn)算符對(duì)數(shù)據(jù)類型是有要求的。如果運(yùn)算符發(fā)現(xiàn),運(yùn)算子的類型與預(yù)期不符,就會(huì)自動(dòng)轉(zhuǎn)換類型。比如,減法運(yùn)算符預(yù)期左右兩側(cè)的運(yùn)算子應(yīng)該是數(shù)值,如果不是,就會(huì)自動(dòng)將它們轉(zhuǎn)為數(shù)值。
-
強(qiáng)制轉(zhuǎn)換
強(qiáng)制轉(zhuǎn)換主要指使用Number()、String()和Boolean()三個(gè)函數(shù),手動(dòng)將各種類型的值,分別轉(zhuǎn)換成數(shù)字、字符串或者布爾值。
使用Number函數(shù),可以將任意類型的值轉(zhuǎn)化成數(shù)值。分成兩種情況討論,一種是參數(shù)是原始類型的值,另一種是參數(shù)是對(duì)象。
/ 數(shù)值:轉(zhuǎn)換后還是原來(lái)的值
Number(324) // 324
// 字符串:如果可以被解析為數(shù)值,則轉(zhuǎn)換為相應(yīng)的數(shù)值
Number('324') // 324
// 字符串:如果不可以被解析為數(shù)值,返回 NaN
Number('324abc') // NaN
// 空字符串轉(zhuǎn)為0
Number('') // 0
// 布爾值:true 轉(zhuǎn)成 1,false 轉(zhuǎn)成 0
Number(true) // 1
Number(false) // 0
// undefined:轉(zhuǎn)成 NaN
Number(undefined) // NaN
// null:轉(zhuǎn)成0
Number(null) // 0
Number函數(shù)將字符串轉(zhuǎn)為數(shù)值,要比parseInt函數(shù)嚴(yán)格很多。基本上,只要有一個(gè)字符無(wú)法轉(zhuǎn)成數(shù)值,整個(gè)字符串就會(huì)被轉(zhuǎn)為NaN。另外,parseInt和Number函數(shù)都會(huì)自動(dòng)過(guò)濾一個(gè)字符串前導(dǎo)和后綴的空格。
Number方法的參數(shù)是對(duì)象時(shí),將返回NaN,除非是包含單個(gè)數(shù)值的數(shù)組。之所以會(huì)這樣,是因?yàn)镹umber背后的轉(zhuǎn)換規(guī)則比較復(fù)雜。
第一步,調(diào)用對(duì)象自身的valueOf方法。如果返回原始類型的值,則直接對(duì)該值使用Number函數(shù),不再進(jìn)行后續(xù)步驟。
第二步,如果valueOf方法返回的還是對(duì)象,則改為調(diào)用對(duì)象自身的toString方法。如果toString方法返回原始類型的值,則對(duì)該值使用Number函數(shù),不再進(jìn)行后續(xù)步驟。
第三步,如果toString方法返回的是對(duì)象,就報(bào)錯(cuò)。
var obj = {x: 1};
Number(obj) // NaN
// 等同于
if (typeof obj.valueOf() === 'object') {
Number(obj.toString());
} else {
Number(obj.valueOf());
}
上面代碼中,Number函數(shù)將obj對(duì)象轉(zhuǎn)為數(shù)值。背后發(fā)生了一連串的操作,首先調(diào)用obj.valueOf方法, 結(jié)果返回對(duì)象本身;于是,繼續(xù)調(diào)用obj.toString方法,這時(shí)返回字符串[object Object],對(duì)這個(gè)字符串使用Number函數(shù),得到NaN。如果toString方法返回的不是原始類型的值,結(jié)果就會(huì)報(bào)錯(cuò)。
var obj = {
valueOf: function () {
return {};
},
toString: function () {
return {};
}
};
Number(obj)
// TypeError: Cannot convert object to primitive value
Number({
valueOf: function () {
return 2;
}
})
// 2
Number({
toString: function () {
return 3;
}
})
// 3
Number({
valueOf: function () {
return 2;
},
toString: function () {
return 3;
}
})
// 2
從上例還可以看到,valueOf和toString方法,都是可以自定義的。上面代碼對(duì)三個(gè)對(duì)象使用Number函數(shù)。第一個(gè)對(duì)象返回valueOf方法的值,第二個(gè)對(duì)象返回toString方法的值,第三個(gè)對(duì)象表示valueOf方法先于toString方法執(zhí)行。
String函數(shù)可以將任意類型的值轉(zhuǎn)化成字符串,轉(zhuǎn)換規(guī)則如下。
- 原始類型>> 數(shù)值:轉(zhuǎn)為相應(yīng)的字符串;字符串:轉(zhuǎn)換后還是原來(lái)的值;布爾值:
true轉(zhuǎn)為字符串“true”,false轉(zhuǎn)為字符串“false”;undefined:轉(zhuǎn)為字符串“undefined”;null:轉(zhuǎn)為字符串“null”。 - 對(duì)象>>
String方法的參數(shù)如果是對(duì)象,返回一個(gè)類型字符串;如果是數(shù)組,返回該數(shù)組的字符串形式。
String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
String方法背后的轉(zhuǎn)換規(guī)則,與Number方法基本相同,只是互換了valueOf方法和toString方法的執(zhí)行順序。
- 先調(diào)用對(duì)象自身的
toString方法。如果返回原始類型的值,則對(duì)該值使用String函數(shù),不再進(jìn)行以下步驟。 - 如果
toString方法返回的是對(duì)象,再調(diào)用原對(duì)象的valueOf方法。如果valueOf方法返回原始類型的值,則對(duì)該值使用String函數(shù),不再進(jìn)行以下步驟。 - 如果
valueOf方法返回的是對(duì)象,就報(bào)錯(cuò)。
String({
toString: function () {
return 3;
}
})
// "3"
String({
valueOf: function () {
return 2;
}
})
// "[object Object]"
String({
valueOf: function () {
return 2;
},
toString: function () {
return 3;
}
})
// "3"
上面是通過(guò)自定義toString方法,改變返回值的例子。上面代碼對(duì)三個(gè)對(duì)象使用String函數(shù)。第一個(gè)對(duì)象返回toString方法的值(數(shù)值3),第二個(gè)對(duì)象返回的還是toString方法的值([object Object]),第三個(gè)對(duì)象表示toString方法先于valueOf方法執(zhí)行。
Boolean函數(shù)可以將任意類型的值轉(zhuǎn)為布爾值。它的轉(zhuǎn)換規(guī)則相對(duì)簡(jiǎn)單:除了以下五個(gè)值的轉(zhuǎn)換結(jié)果為false,其他的值全部為true。注意,所有對(duì)象(包括空對(duì)象)的轉(zhuǎn)換結(jié)果都是true,甚至連false對(duì)應(yīng)的布爾對(duì)象new Boolean(false)也是true
undefined、null、-0或+0、NaN、‘ ’(空字符串)為false。
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
自動(dòng)轉(zhuǎn)換,它是以強(qiáng)制轉(zhuǎn)換為基礎(chǔ)的。遇到以下三種情況時(shí),JavaScript 會(huì)自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型,即轉(zhuǎn)換是自動(dòng)完成的,用戶不可見(jiàn)。
第一種情況,不同類型的數(shù)據(jù)互相運(yùn)算。
第二種情況,對(duì)非布爾值類型的數(shù)據(jù)求布爾值。
第三種情況,對(duì)非數(shù)值類型的值使用一元運(yùn)算符(即+和-)。
第一種情況
123 + 'abc' // "123abc"
第二種情況
if ('abc') {
console.log('hello')
} // "hello"
第三種情況
+ {foo: 'bar'} // NaN
- [1, 2, 3] // NaN
自動(dòng)轉(zhuǎn)換的規(guī)則是這樣的:預(yù)期什么類型的值,就調(diào)用該類型的轉(zhuǎn)換函數(shù)。比如,某個(gè)位置預(yù)期為字符串,就調(diào)用String函數(shù)進(jìn)行轉(zhuǎn)換。如果該位置即可以是字符串,也可能是數(shù)值,那么默認(rèn)轉(zhuǎn)為數(shù)值。
JavaScript 遇到預(yù)期為布爾值的地方(比如if語(yǔ)句的條件部分),就會(huì)將非布爾值的參數(shù)自動(dòng)轉(zhuǎn)換為布爾值。系統(tǒng)內(nèi)部會(huì)自動(dòng)調(diào)用Boolean函數(shù)。下面兩種寫法,有時(shí)也用于將一個(gè)表達(dá)式轉(zhuǎn)為布爾值。它們內(nèi)部調(diào)用的也是Boolean函數(shù)。
// 寫法一
expression ? true : false
// 寫法二
!! expression
JavaScript 遇到預(yù)期為字符串的地方,就會(huì)將非字符串的值自動(dòng)轉(zhuǎn)為字符串。具體規(guī)則是,先將復(fù)合類型的值轉(zhuǎn)為原始類型的值,再將原始類型的值轉(zhuǎn)為字符串。
字符串的自動(dòng)轉(zhuǎn)換,主要發(fā)生在字符串的加法運(yùn)算時(shí)。當(dāng)一個(gè)值為字符串,另一個(gè)值為非字符串,則后者轉(zhuǎn)為字符串。
'5' + 1 // '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object Object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"
JavaScript 遇到預(yù)期為數(shù)值的地方,就會(huì)將參數(shù)值自動(dòng)轉(zhuǎn)換為數(shù)值。系統(tǒng)內(nèi)部會(huì)自動(dòng)調(diào)用Number函數(shù)。除了加法運(yùn)算符(+)有可能把運(yùn)算子轉(zhuǎn)為字符串,其他運(yùn)算符都會(huì)把運(yùn)算子自動(dòng)轉(zhuǎn)成數(shù)值。
'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
'1' - 1 // 0
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN
注意:
null轉(zhuǎn)為數(shù)值時(shí)為0,而undefined轉(zhuǎn)為數(shù)值時(shí)為NaN。
錯(cuò)誤處理機(jī)制
-
Error 實(shí)例對(duì)象
JavaScript 解析或運(yùn)行時(shí),一旦發(fā)生錯(cuò)誤,引擎就會(huì)拋出一個(gè)錯(cuò)誤對(duì)象。JavaScript 原生提供Error構(gòu)造函數(shù),所有拋出的錯(cuò)誤都是這個(gè)構(gòu)造函數(shù)的實(shí)例。
var err = new Error('出錯(cuò)了');
err.message // "出錯(cuò)了"
上面代碼中,我們調(diào)用Error構(gòu)造函數(shù),生成一個(gè)實(shí)例對(duì)象err。Error構(gòu)造函數(shù)接受一個(gè)參數(shù),表示錯(cuò)誤提示,可以從實(shí)例的message屬性讀到這個(gè)參數(shù)。拋出Error實(shí)例對(duì)象以后,整個(gè)程序就中斷在發(fā)生錯(cuò)誤的地方,不再往下執(zhí)行。
JavaScript 語(yǔ)言標(biāo)準(zhǔn)只提到,Error實(shí)例對(duì)象必須有message屬性,表示出錯(cuò)時(shí)的提示信息,沒(méi)有提到其他屬性。大多數(shù) JavaScript 引擎,對(duì)Error實(shí)例還提供name和stack屬性,分別表示錯(cuò)誤的名稱和錯(cuò)誤的堆棧,但它們是非標(biāo)準(zhǔn)的,不是每種實(shí)現(xiàn)都有。
message:錯(cuò)誤提示信息
name:錯(cuò)誤名稱(非標(biāo)準(zhǔn)屬性)
stack:錯(cuò)誤的堆棧(非標(biāo)準(zhǔn)屬性)
if (error.name) {
console.log(error.name + ': ' + error.message);
}
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
上面代碼中,錯(cuò)誤堆棧的最內(nèi)層是throwit函數(shù),然后是catchit函數(shù),最后是函數(shù)的運(yùn)行環(huán)境。
-
原生錯(cuò)誤類型
Error實(shí)例對(duì)象是最一般的錯(cuò)誤類型,在它的基礎(chǔ)上,JavaScript 還定義了其他6種錯(cuò)誤對(duì)象。也就是說(shuō),存在Error的6個(gè)派生對(duì)象。
SyntaxError對(duì)象是解析代碼時(shí)發(fā)生的語(yǔ)法錯(cuò)誤。下面代碼的錯(cuò)誤,都是在語(yǔ)法解析階段就可以發(fā)現(xiàn),所以會(huì)拋出SyntaxError。第一個(gè)錯(cuò)誤提示是“token 非法”,第二個(gè)錯(cuò)誤提示是“字符串不符合要求”。
// 變量名錯(cuò)誤
var 1a;
// Uncaught SyntaxError: Invalid or unexpected token
// 缺少括號(hào)
console.log 'hello');
// Uncaught SyntaxError: Unexpected string
ReferenceError對(duì)象是引用一個(gè)不存在的變量時(shí)發(fā)生的錯(cuò)誤。另一種觸發(fā)場(chǎng)景是,將一個(gè)值分配給無(wú)法分配的對(duì)象,比如對(duì)函數(shù)的運(yùn)行結(jié)果或者this賦值。
// 使用一個(gè)不存在的變量
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined
// 等號(hào)左側(cè)不是變量
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment
// this 對(duì)象不能手動(dòng)賦值
this = 1
// ReferenceError: Invalid left-hand side in assignment
上面代碼對(duì)函數(shù)console.log的運(yùn)行結(jié)果和this賦值,結(jié)果都引發(fā)了ReferenceError錯(cuò)誤。
RangeError對(duì)象是一個(gè)值超出有效范圍時(shí)發(fā)生的錯(cuò)誤。主要有幾種情況,一是數(shù)組長(zhǎng)度為負(fù)數(shù),二是Number對(duì)象的方法參數(shù)超出范圍,以及函數(shù)堆棧超過(guò)最大值。
// 數(shù)組長(zhǎng)度不得為負(fù)數(shù)
new Array(-1)
// Uncaught RangeError: Invalid array length
TypeError對(duì)象是變量或參數(shù)不是預(yù)期類型時(shí)發(fā)生的錯(cuò)誤。比如,對(duì)字符串、布爾值、數(shù)值等原始類型的值使用new命令,就會(huì)拋出這種錯(cuò)誤,因?yàn)?code>new命令的參數(shù)應(yīng)該是一個(gè)構(gòu)造函數(shù)。
new 123
// Uncaught TypeError: number is not a func
var obj = {};
obj.unknownMethod()
// Uncaught TypeError: obj.unknownMethod is not a function
上面代碼的第二種情況,調(diào)用對(duì)象不存在的方法,也會(huì)拋出TypeError錯(cuò)誤,因?yàn)?code>obj.unknownMethod的值是undefined,而不是一個(gè)函數(shù)。
URIError對(duì)象是 URI 相關(guān)函數(shù)的參數(shù)不正確時(shí)拋出的錯(cuò)誤,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()這六個(gè)函數(shù)。
decodeURI('%2')
// URIError: URI malformed
eval函數(shù)沒(méi)有被正確執(zhí)行時(shí),會(huì)拋出EvalError錯(cuò)誤。該錯(cuò)誤類型已經(jīng)不再使用了,只是為了保證與以前代碼兼容,才繼續(xù)保留。
以上這6種派生錯(cuò)誤,連同原始的
Error對(duì)象,都是構(gòu)造函數(shù)。開(kāi)發(fā)者可以使用它們,手動(dòng)生成錯(cuò)誤對(duì)象的實(shí)例。這些構(gòu)造函數(shù)都接受一個(gè)參數(shù),代表錯(cuò)誤提示信息(message)。
var err1 = new Error('出錯(cuò)了!');
var err2 = new RangeError('出錯(cuò)了,變量超出有效范圍!');
var err3 = new TypeError('出錯(cuò)了,變量類型無(wú)效!');
err1.message // "出錯(cuò)了!"
err2.message // "出錯(cuò)了,變量超出有效范圍!"
err3.message // "出錯(cuò)了,變量類型無(wú)效!"
-
自定義錯(cuò)誤
除了 JavaScript 原生提供的七種錯(cuò)誤對(duì)象,還可以定義自己的錯(cuò)誤對(duì)象。
function UserError(message) {
this.message = message || '默認(rèn)信息';
this.name = 'UserError';
}
UserError.prototype = new Error();
UserError.prototype.constructor = UserError;
new UserError('這是自定義的錯(cuò)誤!');
上面代碼自定義一個(gè)錯(cuò)誤對(duì)象UserError,讓它繼承Error對(duì)象。然后,就可以生成這種自定義類型的錯(cuò)誤了。
-
throw語(yǔ)句
throw語(yǔ)句的作用是手動(dòng)中斷程序執(zhí)行,拋出一個(gè)錯(cuò)誤。下面代碼中,如果變量x小于等于0,就手動(dòng)拋出一個(gè)錯(cuò)誤,告訴用戶x的值不正確,整個(gè)程序就會(huì)在這里中斷執(zhí)行??梢钥吹剑?code>throw拋出的錯(cuò)誤就是它的參數(shù),這里是一個(gè)Error實(shí)例。
if (x <= 0) {
throw new Error('x 必須為正數(shù)');
}
// Uncaught ReferenceError: x is not defined
throw也可以拋出自定義錯(cuò)誤。
function UserError(message) {
this.message = message || '默認(rèn)信息';
this.name = 'UserError';
}
throw new UserError('出錯(cuò)了!');
// Uncaught UserError {message: "出錯(cuò)了!", name: "UserError"}
上面代碼中,throw拋出的是一個(gè)UserError實(shí)例。實(shí)際上,throw可以拋出任何類型的值。也就是說(shuō),它的參數(shù)可以是任何值。對(duì)于 JavaScript 引擎來(lái)說(shuō),遇到throw語(yǔ)句,程序就中止了。引擎會(huì)接收到throw拋出的信息,可能是一個(gè)錯(cuò)誤實(shí)例,也可能是其他類型的值。
// 拋出一個(gè)字符串
throw 'Error!';
// Uncaught Error!
// 拋出一個(gè)數(shù)值
throw 42;
// Uncaught 42
// 拋出一個(gè)布爾值
throw true;
// Uncaught true
// 拋出一個(gè)對(duì)象
throw {
toString: function () {
return 'Error!';
}
};
// Uncaught {toString: ?}
-
try...catch結(jié)構(gòu)
一旦發(fā)生錯(cuò)誤,程序就中止執(zhí)行了。JavaScript 提供了·try...catch·結(jié)構(gòu),允許對(duì)錯(cuò)誤進(jìn)行處理,選擇是否往下執(zhí)行。
try {
throw new Error('出錯(cuò)了!');
} catch (e) {
console.log(e.name + ": " + e.message);
console.log(e.stack);
}
// Error: 出錯(cuò)了!
// at <anonymous>:3:9
// ...
上面代碼中,try代碼塊拋出錯(cuò)誤(上例用的是throw語(yǔ)句),JavaScript 引擎就立即把代碼的執(zhí)行,轉(zhuǎn)到catch代碼塊,或者說(shuō)錯(cuò)誤被catch代碼塊捕獲了。catch接受一個(gè)參數(shù),表示try代碼塊拋出的值。catch代碼塊之中,還可以再拋出錯(cuò)誤,甚至使用嵌套的try...catch結(jié)構(gòu)。
var n = 100;
try {
throw n;
} catch (e) {
if (e <= 50) {
// ...
} else {
throw e;
}
}
// Uncaught 100
為了捕捉不同類型的錯(cuò)誤,catch代碼塊之中可以加入判斷語(yǔ)句。下面代碼中,catch捕獲錯(cuò)誤之后,會(huì)判斷錯(cuò)誤類型(EvalError還是RangeError),進(jìn)行不同的處理。
try {
foo.bar();
} catch (e) {
if (e instanceof EvalError) {
console.log(e.name + ": " + e.message);
} else if (e instanceof RangeError) {
console.log(e.name + ": " + e.message);
}
// ...
}
-
finally 代碼塊
try...catch結(jié)構(gòu)允許在最后添加一個(gè)finally代碼塊,表示不管是否出現(xiàn)錯(cuò)誤,都必需在最后運(yùn)行的語(yǔ)句。
function cleansUp() {
try {
throw new Error('出錯(cuò)了……');
console.log('此行不會(huì)執(zhí)行');
} finally {
console.log('完成清理工作');
}
}
cleansUp()
// 完成清理工作
// Uncaught Error: 出錯(cuò)了……
// at cleansUp (<anonymous>:3:11)
// at <anonymous>:10:1
上面代碼中,由于沒(méi)有catch語(yǔ)句塊,一旦發(fā)生錯(cuò)誤,代碼就會(huì)中斷執(zhí)行。中斷執(zhí)行之前,會(huì)先執(zhí)行finally代碼塊,然后再向用戶提示報(bào)錯(cuò)信息。
例一
function idle(x) {
try {
console.log(x);
return 'result';
} finally {
console.log('FINALLY');
}
}
idle('hello')
// hello
// FINALLY
例二
var count = 0;
function countUp() {
try {
return count;
} finally {
count++;
}
}
countUp()
// 0
count
// 1
上面代碼例一中,try代碼塊沒(méi)有發(fā)生錯(cuò)誤,而且里面還包括return語(yǔ)句,但是finally代碼塊依然會(huì)執(zhí)行。而且,這個(gè)函數(shù)的返回值還是result。上面例二說(shuō)明,return語(yǔ)句的執(zhí)行是排在finally代碼之前,只是等finally代碼執(zhí)行完畢后才返回。return語(yǔ)句里面的count的值,是在finally代碼塊運(yùn)行之前就獲取了。
openFile();
try {
writeFile(Data);
} catch(e) {
handleError(e);
} finally {
closeFile();
}
//執(zhí)行順序
function f() {
try {
console.log(0);
throw 'bug';
} catch(e) {
console.log(1);
return true; // 這句原本會(huì)延遲到 finally 代碼塊結(jié)束再執(zhí)行
console.log(2); // 不會(huì)運(yùn)行
} finally {
console.log(3);
return false; // 這句會(huì)覆蓋掉前面那句 return
console.log(4); // 不會(huì)運(yùn)行
}
console.log(5); // 不會(huì)運(yùn)行
}
var result = f();
// 0
// 1
// 3
result
// false
上面代碼首先打開(kāi)一個(gè)文件,然后在try代碼塊中寫入文件,如果沒(méi)有發(fā)生錯(cuò)誤,則運(yùn)行finally代碼塊關(guān)閉文件;一旦發(fā)生錯(cuò)誤,則先使用catch代碼塊處理錯(cuò)誤,再使用finally代碼塊關(guān)閉文件。
編程風(fēng)格
代碼縮進(jìn);建議總是使用大括號(hào)明確區(qū)塊;圓括號(hào);建議總是在行尾加上分號(hào)(for、while、do...while不需要分號(hào));全局變量建議用大寫來(lái)區(qū)分;盡量不要是用with語(yǔ)句;相等和嚴(yán)格相等盡量使用嚴(yán)格相等;建議不要將不同目的的語(yǔ)句,合并成一行;建議自增(++)和自減(--)運(yùn)算符盡量使用+=和-=代替;盡量不要使用switch...case,用其他方式來(lái)代替。
function doAction(action) {
switch (action) {
case 'hack':
return 'hack';
break;
case 'slash':
return 'slash';
break;
case 'run':
return 'run';
break;
default:
throw new Error('Invalid action.');
}
}
//可以改寫成對(duì)象結(jié)構(gòu)來(lái)代替
function doAction(action) {
var actions = {
'hack': function () {
return 'hack';
},
'slash': function () {
return 'slash';
},
'run': function () {
return 'run';
}
};
if (typeof actions[action] !== 'function') {
throw new Error('Invalid action.');
}
return actions[action]();
}
console 對(duì)象與控制臺(tái)
console對(duì)象是 JavaScript 的原生對(duì)象,它有點(diǎn)像 Unix 系統(tǒng)的標(biāo)準(zhǔn)輸出stdout和標(biāo)準(zhǔn)錯(cuò)誤stderr,可以輸出各種信息到控制臺(tái),并且還提供了很多有用的輔助方法。console的常見(jiàn)用途有兩個(gè):調(diào)試程序,顯示網(wǎng)頁(yè)代碼運(yùn)行時(shí)的錯(cuò)誤信息;提供了一個(gè)命令行接口,用來(lái)與網(wǎng)頁(yè)代碼互動(dòng)。
打開(kāi)開(kāi)發(fā)者工具以后,頂端有多個(gè)面板。
- Elements:查看網(wǎng)頁(yè)的 HTML 源碼和 CSS 代碼。
- Resources:查看網(wǎng)頁(yè)加載的各種資源文件(比如代碼文件、字體文件 CSS 文件等),以及在硬盤上創(chuàng)建的各種內(nèi)容(比如本地緩存、Cookie、Local Storage等)。
- Network:查看網(wǎng)頁(yè)的 HTTP 通信情況。
- Sources:查看網(wǎng)頁(yè)加載的腳本源碼。
- Timeline:查看各種網(wǎng)頁(yè)行為隨時(shí)間變化的情況。
- Performance:查看網(wǎng)頁(yè)的性能情況,比如 CPU 和內(nèi)存消耗。
- Console:用來(lái)運(yùn)行 JavaScript 命令。
-
console對(duì)象提供的各種靜態(tài)方法,用來(lái)與控制臺(tái)窗口互動(dòng)。
console.log(),console.info(),console.debug()
console.log方法用于在控制臺(tái)輸出信息。它可以接受一個(gè)或多個(gè)參數(shù),將它們連接起來(lái)輸出。
如果第一個(gè)參數(shù)是格式字符串(使用了格式占位符),console.log方法將依次用后面的參數(shù)替換占位符,然后再進(jìn)行輸出。console.log方法支持以下占位符,不同類型的數(shù)據(jù)必須使用對(duì)應(yīng)的占位符。
%s 字符串、%d 整數(shù)、%i 整數(shù)、%f浮點(diǎn)數(shù)、%o 對(duì)象的鏈接、%c CSS 格式字符串
console.log(' %s + %s = %s', 1, 1, 2)
// 1 + 1 = 2
var number = 11 * 9;
var color = 'red';
console.log('%d %s balloons', number, color);
// 99 red balloons
//使用%c占位符時(shí),對(duì)應(yīng)的參數(shù)必須是 CSS 代碼,用來(lái)對(duì)輸出內(nèi)容進(jìn)行 CSS 渲染。
console.log(
'%cThis text is styled!',
'color: red; background: yellow; font-size: 24px;'
)
console.info是console.log方法的別名,用法完全一樣。只不過(guò)console.info方法會(huì)在輸出信息的前面,加上一個(gè)藍(lán)色圖標(biāo)。
console.debug方法與console.log方法類似,會(huì)在控制臺(tái)輸出調(diào)試信息。但是,默認(rèn)情況下,console.debug輸出的信息不會(huì)顯示,只有在打開(kāi)顯示級(jí)別在verbose的情況下,才會(huì)顯示。console.warn方法和console.error方法也是在控制臺(tái)輸出信息,它們與log方法的不同之處在于,warn方法輸出信息時(shí),在最前面加一個(gè)黃色三角,表示警告;error方法輸出信息時(shí),在最前面加一個(gè)紅色的叉,表示出錯(cuò)。同時(shí),還會(huì)高亮顯示輸出文字和錯(cuò)誤發(fā)生的堆棧。其他方面都一樣。對(duì)于某些復(fù)合類型的數(shù)據(jù),console.table方法可以將其轉(zhuǎn)為表格顯示。
var languages = [
{ name: "JavaScript", fileExtension: ".js" },
{ name: "TypeScript", fileExtension: ".ts" },
{ name: "CoffeeScript", fileExtension: ".coffee" }
];
console.table(languages);
console.count方法用于計(jì)數(shù),輸出它被調(diào)用了多少次。該方法可以接受一個(gè)字符串作為參數(shù),作為標(biāo)簽,對(duì)執(zhí)行次數(shù)進(jìn)行分類。
function greet(user) {
console.count();
return 'hi ' + user;
}
greet('bob')
// : 1
// "hi bob"
greet('alice')
// : 2
// "hi alice"
greet('bob')
// : 3
// "hi bob"
function greet(user) {
console.count(user);
return "hi " + user;
}
greet('bob')
// bob: 1
// "hi bob"
greet('alice')
// alice: 1
// "hi alice"
greet('bob')
// bob: 2
// "hi bob"
console.dir(),console.dirxml()方法用來(lái)對(duì)一個(gè)對(duì)象進(jìn)行檢查(inspect),并以易于閱讀和打印的格式顯示。dir方法對(duì)于輸出 DOM 對(duì)象非常有用,因?yàn)闀?huì)顯示 DOM 對(duì)象的所有屬性。dirxml方法主要用于以目錄樹(shù)的形式,顯示 DOM 節(jié)點(diǎn)。如果參數(shù)不是 DOM 節(jié)點(diǎn),而是普通的 JavaScript 對(duì)象,console.dirxml等同于console.dir。
console.dir(document.body);
console.dirxml(document.body);
console.time(),console.timeEnd()這兩個(gè)方法用于計(jì)時(shí),可以算出一個(gè)操作所花費(fèi)的準(zhǔn)確時(shí)間。time方法表示計(jì)時(shí)開(kāi)始,timeEnd方法表示計(jì)時(shí)結(jié)束。它們的參數(shù)是計(jì)時(shí)器的名稱。調(diào)用timeEnd方法之后,控制臺(tái)會(huì)顯示“計(jì)時(shí)器名稱: 所耗費(fèi)的時(shí)間”。
console.time('Array initialize');
var array= new Array(1000000);
for (var i = array.length - 1; i >= 0; i--) {
array[i] = new Object();
};
console.timeEnd('Array initialize');
// Array initialize: 1914.481ms
console.group和console.groupEnd這兩個(gè)方法用于將顯示的信息分組。它只在輸出大量信息時(shí)有用,分在一組的信息,可以用鼠標(biāo)折疊/展開(kāi)。console.groupCollapsed方法與console.group方法很類似,唯一的區(qū)別是該組的內(nèi)容,在第一次顯示時(shí)是收起的(collapsed),而不是展開(kāi)的。
console.trace方法顯示當(dāng)前執(zhí)行的代碼在堆棧中的調(diào)用路徑。console.clear方法用于清除當(dāng)前控制臺(tái)的所有輸出,將光標(biāo)回置到第一行。如果用戶選中了控制臺(tái)的“Preserve log”選項(xiàng),console.clear方法將不起作用。
瀏覽器控制臺(tái)中,除了使用console對(duì)象,還可以使用一些控制臺(tái)自帶的命令行方法。(了解)。
debugger語(yǔ)句主要用于除錯(cuò),作用是設(shè)置斷點(diǎn)。如果有正在運(yùn)行的除錯(cuò)工具,程序運(yùn)行到debugger語(yǔ)句時(shí)會(huì)自動(dòng)停下。如果沒(méi)有除錯(cuò)工具,debugger語(yǔ)句不會(huì)產(chǎn)生任何結(jié)果,JavaScript 引擎自動(dòng)跳過(guò)這一句。
for(var i = 0; i < 5; i++){
console.log(i);
if (i === 2) debugger;
}