內置型別
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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/109911.html
標籤:JavaScript
上一篇:前端程式員的進階

