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