內(nèi)置類型
JS 中七種內(nèi)置類型(null,undefined,boolean,number,string,symbol,object)又分為兩大類型
兩大類型:
- 基本類型:
null ,undefined ,boolean ,number ,string ,symbol
- 引用類型Object:
Array ,Function , Date , RegExp 等

存放位置:
- 基本數(shù)據(jù)類型:基本類型值在內(nèi)存中占據(jù)固定大小,直接存儲(chǔ)在棧內(nèi)存中的數(shù)據(jù)
- 引用數(shù)據(jù)類型:引用類型在棧中存儲(chǔ)了指針,這個(gè)指針指向堆內(nèi)存中的地址,真實(shí)的數(shù)據(jù)存放在堆內(nèi)存里。

值的可變性:
- 基本數(shù)據(jù)類型: 值不可變,javascript中的原始值(undefined、null、布爾值、數(shù)字和字符串)是不可更改的
- 引用數(shù)據(jù)類型:引用類型是可以直接改變其值的
//基本數(shù)據(jù)類型
var str = "abc";
console.log(str[1]="f"); // f
console.log(str); // abc
//引用數(shù)據(jù)類型
var a = [1,2,3];
a[1] = 5;
console.log(a[1]); // 5
比較:
- 基本數(shù)據(jù)類型: 基本類型的比較是值的比較,只要它們的值相等就認(rèn)為他們是相等的
- 引用數(shù)據(jù)類型: 引用數(shù)據(jù)類型的比較是引用的比較,看其的引用是否指向同一個(gè)對象
//基本數(shù)據(jù)類型
var a = 1;
var b = 1;
console.log(a === b);//true
//引用數(shù)據(jù)類型
var a = [1,2,3];
var b = [1,2,3];
console.log(a === b); // false
//雖然變量 a 和變量 b 都是表示一個(gè)內(nèi)容為 1,2,3 的數(shù)組,
//但是其在內(nèi)存中的位置不一樣,也就是說變量 a 和變量 b 指向的不是同一個(gè)對象,所以他們是不相等的
Typeof
typeof 對于基本類型,除了 null 都可以顯示正確的類型,對于 null 來說,雖然它是基本類型,但是會(huì)顯示 object ,這是一個(gè)存在很久了的 Bug, 這與JavaScript的歷史有關(guān),null被設(shè)計(jì)成可以自動(dòng)轉(zhuǎn)為0
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof b // b 沒有聲明,但是還會(huì)顯示 undefined
typeof null // 'object'
typeof 對于對象,除了函數(shù)都會(huì)顯示 object
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
獲得一個(gè)變量的正確類型,可以通過 Object.prototype.toString.call(xx) 。這樣我們就可以獲得類似 [object Type] 的字符串。
Object.prototype.toString.call(22) //"[object Number]"
Object.prototype.toString.call('22') //"[object String]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(a) //"[object Undefined]"
Object.prototype.toString.call(true) //"[object Boolean]"
Object.prototype.toString.call({a:1}) //"[object Object]"
typeof的安全防范機(jī)制
檢查 DEBUG 變量是否已被聲明
if (DEBUG) {
console.log('Debugging is starting');
}
// 報(bào)錯(cuò) ReferenceError 錯(cuò)誤
if (typeof DEBUG !== 'undefined') {
console.log('Debugging is starting');
}
基本類型
null
- Null 類型也只有一個(gè)值,就是 null,它的語義表示空值
- null 是 JavaScript 關(guān)鍵字
常見問題:null 和 undefined 的區(qū)別?
**
null表示"沒有對象",即該處不應(yīng)該有值。典型用法是:
(1) 作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象。
(2) 作為對象原型鏈的終點(diǎn)。
Object.getPrototypeOf(Object.prototype)
// null
undefined表示"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒有定義。典型用法是:
(1)變量被聲明了,但沒有賦值時(shí),就等于undefined。
(2) 調(diào)用函數(shù)時(shí),應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于undefined。
(3)對象沒有賦值的屬性,該屬性的值為undefined。
(4)函數(shù)沒有返回值時(shí),默認(rèn)返回undefined。
//變量被聲明了,但沒有賦值時(shí),就等于undefined。
var i;
i // undefined
//調(diào)用函數(shù)時(shí),應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于undefined。
function f(x){console.log(x)}
f() // undefined
//對象沒有賦值的屬性,該屬性的值為undefined。
var o = new Object();
o.p // undefined
//函數(shù)沒有返回值時(shí),默認(rèn)返回undefined。
var x = f();
x // undefined
undefined
- Undefined 類型表示未定義,它的類型只有一個(gè)值,就是 undefined。
- 任何變量在賦值前是 Undefined 類型、值為 undefined
- undefined 是一個(gè)變量,而并非是一個(gè)關(guān)鍵字
常見問題:為什么有的編程規(guī)范要求用 void 0 代替 undefined?
因?yàn)?JavaScript 的代碼 undefined 是一個(gè)變量,而并非是一個(gè)關(guān)鍵字,這是 JavaScript 語言公認(rèn)的設(shè)計(jì)失誤之一,所以,我們?yōu)榱吮苊鉄o意中被篡改,建議使用 void 0 來獲取 undefined 值,void 后面隨便跟上一個(gè)便組成表達(dá)式,返回就是 undefined
let a
a === undefined //true
a //undefined
void 0 //undefined void 后面隨便跟上一個(gè)組成表達(dá)式返回就是 undefined
a === void 0 //true
boolean
Boolean 類型有兩個(gè)值, true 和 false
number
JavaScript 中的 Number 類型基本符合 IEEE 754-2008 規(guī)定的雙精度浮點(diǎn)數(shù)規(guī)則,但是 JavaScript 為了表達(dá)幾個(gè)額外的語言場景(比如不讓除以 0 出錯(cuò),而引入了無窮大的概念),規(guī)定了幾個(gè)例外情況:
- NaN,占用了 9007199254740990,這原本是符合 IEEE 規(guī)則的數(shù)字;
- Infinity,無窮大;
- -Infinity,負(fù)無窮大。
常見問題:0.1 + 0.2 不是等于 0.3 么?為什么 JavaScript 里不是這樣的?
這里錯(cuò)誤的不是結(jié)論,而是比較的方法,正確的比較方法是使用 JavaScript 提供的最小精度值:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
檢查等式左右兩邊差的絕對值是否小于最小精度,才是正確的比較浮點(diǎn)數(shù)的方法。這段代碼結(jié)果就是 true 了。
string
常見問題:字符串有最大長度嗎?
- String 用于表示文本數(shù)據(jù)。String 有最大長度是 2^53 - 1,這在一般開發(fā)中都是夠用的,但是有趣的是,這個(gè)所謂最大長度,并不完全是你理解中的字符數(shù)
- String 的意義并非“字符串”,而是字符串的 UTF16 編碼,我們字符串的操作 charAt、charCodeAt、length 等方法針對的都是 UTF16 編碼。所以,字符串的最大長度,實(shí)際上是受字符串的編碼長度影響的
symbol
Symbol 是 ES6 中引入的新類型,它是一切非字符串的對象 key 的集合,在 ES6 規(guī)范中,整個(gè)對象系統(tǒng)被用 Symbol 重塑。
//創(chuàng)建
var mySymbol = Symbol("my symbol");
引用類型
Object
Object 表示對象的意思,它是一切有形和無形物體的總稱。
在 JavaScript 中,對象的定義是“屬性的集合”。
屬性分為數(shù)據(jù)屬性和訪問器屬性,二者都是 key-value 結(jié)構(gòu),key 可以是字符串或者 Symbol 類型
現(xiàn)象:類型轉(zhuǎn)換
四則運(yùn)算符
-
加法
-
其他運(yùn)算符
- 只要其中一方是數(shù)字,那么另一方就會(huì)被轉(zhuǎn)為數(shù)字
1 + '1' // '11'
true + true // 2
4 + [1,2,3] // "41,2,3"
4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN
== 操作符
JavaScript 中的“ == ”運(yùn)算,因?yàn)樵噲D實(shí)現(xiàn)跨類型的比較,它的規(guī)則復(fù)雜到幾乎沒人可以記住, 它屬于設(shè)計(jì)失誤,并非語言中有價(jià)值的部分,很多實(shí)踐中推薦禁止使用“ ==”,而要求程序員進(jìn)行顯式地類型轉(zhuǎn)換后,用 === 比較
比較運(yùn)算符
1.如果是對象,則轉(zhuǎn)換為原始類型再比較值
2.如果是字符串,就通過unicode 字符索引來比較
'10'.charCodeAt() //49
'厲害'.charCodeAt() //21385
'10' < '厲害' //true
'10' > '厲害' //false
對象轉(zhuǎn)基本類型
對象在轉(zhuǎn)換類型的時(shí)候,會(huì)調(diào)用內(nèi)置的[[ToPrimitive]] 函數(shù)
轉(zhuǎn)換流程:
- 如果已經(jīng)是原始類型了,就不需要轉(zhuǎn)換了(因?yàn)榭梢灾貙?code>Symbol.toPrimitive)
- 如果需要轉(zhuǎn)換為字符串類型,則直接調(diào)用
toString 方法,轉(zhuǎn)換為基礎(chǔ)類型的話就返回轉(zhuǎn)換的值。
- 如果不是字符串類型,則先調(diào)用
valueOf 方法,結(jié)果不是基礎(chǔ)類型的話再調(diào)用toString 方法
- 如果以上處理后,都沒有返回原始類型,就會(huì)報(bào)錯(cuò)
注意:
Symbol.toPrimitive ,有該方法時(shí)則只調(diào)用該方法,優(yōu)先級(jí)最高
- 無symbol時(shí)
valueOf 高于 toString
let a = {
valueOf() {
return 0;
},
toString() {
return '1';
},
[Symbol.toPrimitive]() {
return 2;
}
}
1 + a // => 3
'1' + a // => '12'
裝箱轉(zhuǎn)換
JS引擎有意去模糊“對象”和“基本類型”之間的關(guān)系, 遇到"."時(shí),JS引擎會(huì)臨時(shí)幫我們做一層“裝箱轉(zhuǎn)換”,這里就是 new String() 生成一個(gè)“臨時(shí)對象”
裝箱轉(zhuǎn)換,正是把基本類型轉(zhuǎn)換為對應(yīng)的對象,它是類型轉(zhuǎn)換中一種相當(dāng)重要的種類
// Number
1
new Number(1)
// String
'aaa'
new String('aaa')
// Boolean
true
new Boolean(true)
Symbol不能new,我們用特殊的方法把它new出來
Object(Symbol('aaa'))
// 或者
(function(){return this}).call(Symbol('aaa'))
拆箱轉(zhuǎn)換
JS中拆箱轉(zhuǎn)換是調(diào)用了對象的toPrimitive方法來拆箱
它會(huì)依次嘗試使用valueOf toString來轉(zhuǎn)換
如果沒有valueOf toString方法,或者這2個(gè)方法轉(zhuǎn)換出來的都是非基本類型,則報(bào)錯(cuò)
參考鏈接:
https://github.com/amandakelake/blog/issues/34
https:///docs/frontend/#%E5%AF%B9%E8%B1%A1%E8%BD%AC%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B
|