1 類型
1.1 js有七種內(nèi)置類型
1 undefined 2 boolean 3 number 4 string 5 object 6 null 7 symbol
- typeof undefined === "undefined"
- typeof true === "boolean"; // true
- typeof 42 === "number"; // true
- typeof "42" === "string"; // true
- typeof { life: 42 } === "object"; // true
- typeof Symbol() === "symbol"; // true
但是null稍微特殊
typeof null === "object"; // true
所以如果檢測一個值是否為null,需要
var a = null;
(!a && typeof a === "object"); // true
1.2 JavaScript 中的變量是沒有類型的,只有值才有誓琼。變量可以隨時持有任何類型的值
換個角度來理解就是频伤,JavaScript 不做”類型強(qiáng)制“劳翰。
在對變量執(zhí)行 typeof 操作時抽减,得到的結(jié)果并不是該變量的類型盒发,而是該變量持有的值的類
型郁竟,因為 JavaScript 中的變量沒有類型玛迄。
1.3 undefined && undeclared
undefined 是值的一種。undeclared 則表示變量還沒有被聲明過棚亩。
遺憾的是蓖议,JavaScript 卻將它們混為一談,在我們試圖訪問 "undeclared" 變量時這樣報
錯:ReferenceError: a is not defined蔑舞,并且 typeof 對 undefined 和 undeclared 變量都返回
"undefined"拒担。
typeof undefined == "undefined"
typeof undeclared == "undefined"
2 值
簡單值(即標(biāo)量基本類型值,scalar primitive)總是通過值復(fù)制的方式來賦值 / 傳遞攻询,包括
null从撼、undefined、字符串钧栖、數(shù)字低零、布爾和 ES6 中的 symbol。
復(fù)合值(compound value)——對象(包括數(shù)組和封裝對象拯杠,參見第 3 章)和函數(shù)掏婶,則總 是通過引用復(fù)制的方式來賦值 / 傳遞。
var a = 2;
var b = a; // b是a的值的一個副本
b++;
a; // 2
b; // 3
var c = [1,2,3];
var d = c; // d是[1,2,3]的一個引用
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]
在上述代碼中潭陪,a雄妥,b分別指向 值 的兩個復(fù)本。a依溯,b的改變互不影響老厌。
c,d分別指向 值 的兩個引用黎炉,而引用都指向同樣的一個對象 [1,2,3]枝秤,所以c,d的改變是對于所指對象的改變慷嗜。
function foo(x) {
x.push( 4 );
x; // [1,2,3,4]
// 然后
x = [4,5,6];
x.push( 7 );
x; // [4,5,6,7]
}
var a = [1,2,3];
foo( a );
a; // 是[1,2,3,4]淀弹,不是[4,5,6,7]
其中丹壕,a將 [1,2,3]的引用的復(fù)本,傳給了變量x薇溃。變量x 指向 對象[1,2,3]的引用的復(fù)本菌赖,可以修改其值。
隨后沐序,變量x指向 更改為[4,5,6]的引用盏袄,這一操作并不會影響a的引用。
3 原生函數(shù)
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()——ES6 中新加入的薄啥!
3.1
new String("abc") 創(chuàng)建的是字符串 "abc" 的封裝對象,而非基本類型值 "abc"逛尚。
var a = new String( "abc" );
typeof a; // 是"object"垄惧,不是"String"
a instanceof String; // true
Object.prototype.toString.call( a ); // "[object String]"
3.2 內(nèi)部屬性 [[Class]]
這個屬性無法直接訪問,
一般通過 Object.prototype.toString(..) 來查看绰寞。例如:
Object.prototype.toString.call( [1,2,3] ); // "[object Array]"
Object.prototype.toString.call( /regex-literal/i ); // "[object RegExp]"
4 強(qiáng)制類型轉(zhuǎn)換
4.1 值類型轉(zhuǎn)換
將值從一種類型轉(zhuǎn)換為另一種類型通常稱為類型轉(zhuǎn)換(type casting)到逊,這是顯式的情況;隱式的情況稱為強(qiáng)制類型轉(zhuǎn)換(coercion)滤钱。
也可以這樣來區(qū)分:類型轉(zhuǎn)換發(fā)生在靜態(tài)類型語言的編譯階段觉壶,而強(qiáng)制類型轉(zhuǎn)換則發(fā)生在動態(tài)類型語言的運(yùn)行時(runtime)。
然而在 JavaScript 中通常將它們統(tǒng)稱為強(qiáng)制類型轉(zhuǎn)換件缸,我個人則傾向于用“隱式強(qiáng)制類型
轉(zhuǎn)換”(implicit coercion)和“顯式強(qiáng)制類型轉(zhuǎn)換”(explicit coercion)來區(qū)分铜靶。
例如:
var a = 42;
var b = a + ""; // 隱式強(qiáng)制類型轉(zhuǎn)換
var c = String( a ); // 顯式強(qiáng)制類型轉(zhuǎn)換
4.2 抽象值操作
- toString
- toNumber
其中 true 轉(zhuǎn)換為 1,false 轉(zhuǎn)換為 0他炊。undefined 轉(zhuǎn)換為 NaN争剿,null 轉(zhuǎn)換為 0。
對象(包括數(shù)組)會首先被轉(zhuǎn)換為相應(yīng)的基本類型值痊末,如果返回的是非數(shù)字的基本類型值蚕苇,則再遵循以上規(guī)則將其強(qiáng)制轉(zhuǎn)換為數(shù)字。
為了將值轉(zhuǎn)換為相應(yīng)的基本類型值凿叠,抽象操作 ToPrimitive會首先檢查該值是否有 valueOf() 方法涩笤。
如果有并且返回基本類型值,就使用該值進(jìn)行強(qiáng)制類型轉(zhuǎn)換盒件。如果沒有就使用 toString()的返回值(如果存在)來進(jìn)行強(qiáng)制類型轉(zhuǎn)換蹬碧。
如果 valueOf() 和 toString() 均不返回基本類型值,會產(chǎn)生 TypeError 錯誤履恩。 - toBoolean
以下為假值:
? undefined
? null
? false
? +0锰茉、-0 和 NaN
? ""
4.3 顯式強(qiáng)制類型轉(zhuǎn)換
- 字符串和數(shù)字之間的顯式轉(zhuǎn)換
- 運(yùn)算符的一元形式
2.奇特的 ~ 運(yùn)算符var a = "123" var b = +a // 123 被轉(zhuǎn)換為number
var a = "Hello World"; a.indexOf('H') // 0 ~a.indexOf('H') // -1 Boolean(~indexOf('H')) // true 如果存在值,則indexOf為0或其余正數(shù)切心,那么~為負(fù)數(shù)飒筑,Boolean轉(zhuǎn)換為true a.indexOf('123') // -1 ~a.indexOf('H') // 0 Boolean(~indexOf('H')) // false 如果不存在值片吊,則indexOf為-1,那么~為0协屡,Boolean轉(zhuǎn)換為false
- ~~字位截除
var a = 3.14 ~a // -4 ~~ a // 3 Math.floor( -49.6 ); // -50 ~~-49.6; // -49
- 顯式轉(zhuǎn)換為布爾值
顯式強(qiáng)制類型轉(zhuǎn)換為布爾值最常用的方法是 !! 而不是 Boolean
4.4 隱式強(qiáng)制類型轉(zhuǎn)換
- 字符串和數(shù)字之間的隱式強(qiáng)制類型轉(zhuǎn)換
var a = "42";
var b = "0";
var c = 42;
var d = 0;
a + b; // "420"
c + d; // 42
var a = [1,2];
var b = [3,4];
a + b; // 1,23,4
如果參與運(yùn)算的對象是字符串俏脊,或者可以轉(zhuǎn)換成字符串,則+進(jìn)行字符串拼接操作肤晓。否則執(zhí)行數(shù)字加法爷贫。
因此:a+b=“420”
當(dāng)運(yùn)算對象為對象時,調(diào)用ToPrimitive补憾,調(diào)用valueOf 或者 toString漫萄,獲取[[DefaultValue]]。
因此盈匾,數(shù)組[1,2]被轉(zhuǎn)換為“1腾务,2”“3,4”再進(jìn)行字符串拼接削饵。
var a = "3.14";
var b = a - 0;
b; // 3.14
- 是數(shù)字減法運(yùn)算符岩瘦,因此 a - 0 會將 a 強(qiáng)制類型轉(zhuǎn)換為數(shù)字。
也可以使用 a * 1 和 a / 1窿撬,因為這兩個運(yùn)算符也只適用于數(shù)字启昧,只不過這樣的用法不太常見。
對象的 - 操作與 + 類似:
var a = [3];
var b = [1];
a - b; // 2
- 隱式強(qiáng)制類型轉(zhuǎn)換為布爾值
(1) if (..) 語句中的條件判斷表達(dá)式劈伴。
(2) for ( .. ; .. ; .. ) 語句中的條件判斷表達(dá)式(第二個)密末。
(3) while (..) 和 do..while(..) 循環(huán)中的條件判斷表達(dá)式。
(4) ? : 中的條件判斷表達(dá)式跛璧。
(5) 邏輯運(yùn)算符 ||(邏輯或)和 &&(邏輯與)左邊的操作數(shù)(作為條件判斷表達(dá)式)苏遥。
4.5 || &&
|| 和 && 首先會對第一個操作數(shù)執(zhí)行條件判斷,如果其不是布爾值就先進(jìn)行 ToBoolean 強(qiáng)制類型轉(zhuǎn)換赡模,然后再執(zhí)行條件判斷田炭。
對于 || 來說,如果條件判斷結(jié)果為 true 就返回第一個操作數(shù)的值漓柑,如果為
false 就返回第二個操作數(shù)的值教硫。
&& 則相反,如果條件判斷結(jié)果為 true 就返回第二個操作數(shù)的值辆布,如果為 false 就返回第一個操作數(shù)的值瞬矩。
可以用a && foo() 代替 if(a) { foo() },簡潔
var a = 42;
var b = null;
var c = "foo";
if (a && (b || c)) {
console.log( "yep" );
}
在上述 if 中
1 b||c // “foo”
2 a && (b||c) // "foo"
3 if 隱式類型轉(zhuǎn)換锋玲,將"foo"轉(zhuǎn)為true
4.6 寬松相等和嚴(yán)格相等
== 允許在相等比較中進(jìn)行強(qiáng)制類型轉(zhuǎn)換景用,而 === 不允許。
== 和 === 都會檢查操作數(shù)的類型。區(qū)別在于操作數(shù)類型不同時它們的處理方
式不同伞插。
- 數(shù)字和字符串比較 字符串ToNumber
x = '42'
y = 1
x== y
首先將 ‘42’ 轉(zhuǎn)為 42割粮,轉(zhuǎn)為number,再比較
返回false
- 布爾和其他類型比較 布爾值ToNumber
x = true
y = '42'
x == y
首先媚污,true 轉(zhuǎn)為 1舀瓢,這樣就是 1 == ‘42’
其次,‘42’ 轉(zhuǎn)為 42耗美,再比較
返回false
- 對象和非對象之間的相等比較
(1) 如果 Type(x) 是字符串或數(shù)字京髓,Type(y) 是對象,則返回 x == ToPrimitive(y) 的結(jié)果商架;
(2) 如果 Type(x) 是對象堰怨,Type(y) 是字符串或數(shù)字,則返回 ToPromitive(x) == y 的結(jié)果蛇摸。 - 對象和對象的比較
比較對象所指向的值诚些,是否相等 - <=
在js中,a <= b
被轉(zhuǎn)換為 !(a>b)