「面試指南」解讀JavaScript原始資料類型
JavaScript 有 7 種原始資料類型:
String(字元型)
Number(數值型)
Boolean(布爾值型)
Undefined
Null
Object(對象型)
Symbol(符号型,ES6 中新增資料類型)
通常使用 typeof 檢測其類型(Null,Array,Object 除外),傳回其資料類型值的字元串;
String
字元型:由一系列字元組成的字元串,屬于值類型。
Number
數值型:用來表示數值,屬于值類型,可以用于算術邏輯計算。
Boolean
布爾值型:用表示邏輯是,邏輯非:true,false,屬于值類型。
未定義:定義未指派,或未定義(直接使用會引起異常),特殊的資料類原始資料型。
空:代表一個空指針,特殊的一種原始資料類型。
Object
對象型:以 key-value 的方式代表屬性名與屬性值,由{}組成,不同的屬性以,隔開,JS 中一種重要的引用型原始資料類型。
Symbol
符号型:ES6 新增的一種原始資料類型,主要用于解決屬性名相同一起的沖突問題,每個 Symbol()值都不相同。
3 種基本資料類型:String、Number、Boolean,屬于值類型
var a = '10',
b = 10,
c = true;
console.log('a ' + typeof a); // 結果:a string
console.log('b ' + typeof b); // 結果:b number
console.log('c ' + typeof c); // 結果:c boolean
2 種特殊資料類型:Undefined、Null;
Undefined:
1).未定義,直接使用,報錯;但是直接輸出一個不存在變量的 typeof ,傳回 undefined;
d; // 報錯:ReferenceError: d is not defined
console.log(d); // 報錯:ReferenceError: d is not defined
console.log(typeof dd); // 不報錯,結果:undefined
2).已定義,但是未指派,結果:undefined。
var e;
console.log(e); // 結果不報錯:undefined
console.log('e ' + typeof e); // 結果:e undefined
Null:
曆史原因設計缺陷,最初未設計此類型,當作 object 的一種特殊值。後來作為一種單獨的資料類型獨立出來,為了相容以前的代碼,typeof null 傳回 object 就沒法改變了。
var f = null;
console.log('f ' + typeof f); // 結果: f object
Null 類型的檢測:
function isNull(value) {
if (!value && typeof value === 'object') return true;
return false;
}
console.log(isNull(null)); // 結果:true
console.log(isNull('a')); // 結果:false
console.log(isNull(123)); // 結果:false
console.log(isNull(true)); // 結果:false
1 種引用資料類型:Object;
Object(對象型):一般是基本資料類型的組合,由{}分隔。在{}内部,對象的屬性以 key-value 鍵值對的形式 (name : value) 來定義。屬性之間由,分隔:
var city = { id: 1, name: '北京', value: 'BeiJing' };
有多種定義/尋址/修改方式:
// 直接定義指派
// 關鍵字new定義并指派
var city = new Object();
city.id = 1;
city.name = '北京';
city.value = 'BeiJing';
// defineProperty單個新增或修改某個屬性值
var city = {};
Object.defineProperty(city, 'id', {
value: 1,
writable: true,
configurable: true,
enumerable: true
});// 等價于 city[id]=1,或citys.id=1;
Object.defineProperty(city, 'name', {
value: '北京',
});// 等價于 city[name]='北京',或citys.name='北京';
Object.defineProperty(city, 'value', {
value: 'BeiJing',
});// 等價于 city[value]='BeiJing',或citys.value='BeiJing';
console.log(city); // {id: 1, name: '北京', value: 'BeiJing'}
// defineProperties批量新增或修改屬性值
Object.defineProperties(city, {
id: {
value: 1,
writable: true,
configurable: true,
enumerable: true
},
name: {
value: '北京',
writable: true,
configurable: true,
enumerable: true
value: {
value: 'BeiJing',
writable: true,
configurable: true,
enumerable: true
});
// 等價于 直接指派 city={id: 1, name: '北京', value: 'BeiJing'}
defineProperty:精确地添加或修改對象的屬性這個方法允許修改預設的額外選項(或配置)。
一般具有配置屬性:value(屬性值)、writable(是否可修改)、configurable(是否可删除)、enumerable(是否可枚舉),
預設情況下,使用 Object.defineProperty() 添加的屬性值是不可修改的,
預設值配置:writable:false,configurable:false,enumerable:false。
// 小小說明
// 使用以下方法可以精确配置對象obj:
Object.defineProperty(obj,obj_name,{
value:name_value,
writable:false,// 預設,配置後不可直接指派修改
configurable:false,// 預設,配置後不可使用delete删除
enumerable:false// 預設,配置後不可在for-in、Object.keys()中枚舉
// 示例說明:
var obj={};
// 使用以下方法操作obj,等價于obj={name:'hello'};
Object.defineProperty(obj,name,{
value:'hello',
writable:true,// 預設
configurable:true,// 可删除,可以使用delete obj.name,來删除name屬性;
enumerable:true// 可枚舉
屬性有兩種尋址方式:
// 點方法
var cityName = city.name;
console.log(cityName); // 北京
// 或者方括号方法
var cityName = city[name];
對象可以使用 for-in、Object.keys()來枚舉其屬性
// for-in枚舉屬性
for (const key in city) {
if (city.hasOwnProperty(key)) {
let value = city[key]; // 或者let value = city.key;
console.log(key, value);
// id 1
// name 北京
// value BeiJing
// Object.keys()枚舉屬性
for (let i = 0; i < Object.keys(city).length; i++) {
const key = Object.keys(city)[i];
let value = city[key]; // 或者let value = city.key;
console.log(key, value);
對象的原型、原型鍊、方法繼承另篇總結。
1 種 ES6 新增資料類型:Symbol。
為什麼引入 Symbol?
ES5 的對象屬性名都是字元串,這容易造成屬性名的沖突。比如,你使用了一個他人提供的對象,但又想為這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法産生沖突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的沖突。這就是 ES6 引入 Symbol 的原因。
Symbol 是一種用來解決因對象屬性名沖突,來確定每個屬性名全局唯一的第 7 種新的原始資料類型。
var s = Symbol();
console.log('s ', s, typeof s); // s Symbol() 'symbol'
不可以使用 new 來定義一個 Symbol();因為 Symbol()函數生成的是一個原始資料類型的值類型而非引用類型,不是對象,是以不能添加屬性。基本上,它是一種類似于字元串/數值的資料類型;
var s1 = Symbol();
var s2 = Symbol();
console.log(s1 === s2); // false
Symbol 函數可以接受一個字元串作為參數,表示對 Symbol 執行個體的描述,主要是為了在控制台顯示,或者轉為字元串時,比較容易區分。相同描述的兩個 Symbol,傳回值依然是不相等的,同樣是兩個不同的 Symbol;
var s1 = Symbol('s1');
var s2 = Symbol('s2');
console.log(s1, s2); // Symbol(s1) Symbol(s2)
console.log(s1.toString(), s2.toString()); // "Symbol(s1)" "Symbol(s2)"
var _s1 = Symbol('s1');
console.log(_s1 === s1); // false
但是,Symbol 值可以顯式轉為字元串。
var symb = Symbol('a symbol');
String(symb); // 'Symbol(a symbol)'
symb.toString(); // 'Symbol(a symbol)'
另外,Symbol 值也可以轉為布爾值,但是不能轉為數值。
var symb = Symbol();
Boolean(symb); // true
!symb; // false
if (symb) {
console.log('if symb be true,do somethine.'); // if symb be true,do somethine.
Number(symb); // Uncaught TypeError: Cannot convert a Symbol value to a number
symb + 2; // Uncaught TypeError: Cannot convert a Symbol value to a number
當 Symbol 作為屬性名:
由于每一個 Symbol 值都是不相等的,這意味着 Symbol 值可以作為辨別符,用于對象的屬性名,就能保證不會出現同名的屬性。這對于一個對象由多個子產品構成的情況非常有用,能防止某一個鍵被不小心改寫或覆寫。這也是 Symbol 的設計初衷之一。
var mySymbol = Symbol();
// 第一種寫法
var a = {};
a[mySymbol] = 'Hello!';
// 第二種寫法
var a = {
};
// 第三種寫法
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上寫法都得到同樣結果
a[mySymbol]; // "Hello!"
注意,Symbol 值作為對象屬性名時,不能用點運算符。
a.mySymbol = 'Hello!';
a[mySymbol]; // undefined
a['mySymbol']; // "Hello!"
在對象的内部,使用 Symbol 值定義屬性時,Symbol 值必須放在方括号之中。
let s = Symbol();
let obj = {
// do something
// 為了更簡潔,也可以采用增強的對象寫法
s{
// do something
obj
;
Symbol 的特性使得用來定義一組常量具有很好的優勢,進而保證常量的值都是不一樣的。
Symbol 應用執行個體:消除魔術字元串
魔術字元串:在代碼之中多次出現、與代碼形成強耦合的某一個具體的字元串或者數值。風格良好的代碼,應該盡量消除魔術字元串,改由含義清晰的變量代替。
其中魔術字元串在 switch 條件語句中有大量的展現:
function getArea(shape, options) {
var area = 0;
switch (shape) {
case 'Triangle': // 魔術字元串
area = 0.5 * options.width * options.height;
break;
// other shape
return area;
getArea('Triangle', { width: 100, height: 100 });
// 常量'Triangle' 代碼塊中兩次出現,出現了魔術字元串,不利于修改與維護;
一般是把常量變成變量,即可消除魔術字元串,故上述一般作如下處理:
var shapeType = {
triangle: 'Triangle'
switch (shape) {
case shapeType.triangle:
area = 0.5 * options.width * options.height;
break;
return area;
getArea(shapeType.triangle, { width: 100, height: 100 });
不過上述的 shapeType.triangle 依然存在無法確定唯一的可能,如果使用 Symbol,就會消除這樣可能,使得 switch 可以以可靠的按照設計的方式執行,以上做如下修改即可。
- triangle: 'Triangle'
-
triangle: Symbol()
};
對象中屬性包含 Symbol 的周遊
當 Symbol 作為對象屬性名時,對象的周遊就發生了一些小的變化,該屬性就不會再 for-in 、for-of,循環中出現,也不會在 Object.keys()、Object.getOwnProperNames()、JSON.stringify()中作為屬性傳回了。
不過,它也不是私有屬性,有一個 Object.getOwnPropertySymbols 方法,可以擷取指定對象的所有 Symbol 屬性名。
Object.getOwnPropertySymbols 方法傳回一個數組,成員是目前對象的所有用作屬性名的 Symbol 值。
var obj = {},
a = Symbol('a'),
b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
obj['c'] = "I'm";
obj['d'] = 'a FE Developer!';
// 4種周遊方式的對比:
// 1.使用for-in周遊對象
console.error('for-in周遊對象:');
for (const key in obj) {
console.log('key:' + key);
// 2.使用Object.keys周遊對象
var objKeys_keys = Object.keys(obj);
console.error('Object.keys()周遊對象:');
console.log(objKeys_keys); // ["c","d"]
// 3.使用Object.getOwnProperNames(),周遊對象
var objKeys_ownProper = Object.getOwnPropertyNames(obj);
console.error('Object.getOwnPropertyNames()周遊對象:');
console.log(objKeys_ownProper); // ["c","d]
// 4.使用Object.getOwnPropertySymbols,周遊對象
var objectKeys_symbol = Object.getOwnPropertySymbols(obj);
console.error('Object.getOwnPropertySymbols周遊對象:');
console.log(objectKeys_symbol); // [Symbol(a), Symbol(b)]
// 對比輸出結果:
// for-in周遊對象:["c","d"]
// Object.keys周遊對象:["c","d"]
// Object.getOwnPropertyNames()周遊對象:["c","d"]
// Object.getOwnPropertySymbols周遊對象:[Symbol(a), Symbol(b)]
上述使用 for-in、Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()對對象的周遊做了對比。那麼,有沒有一種方法可以可以枚舉一個對象的所有的屬性呢?
答案是有的:Reflect.keys();
Reflect.keys()周遊對象屬性,不會受 enumerable 影響
什麼是 Reflect?
Reflect 是一個對象,所有屬性和方法都是靜态的,類似于 Math()函數,提供以下靜态方法:
Reflect.apply():對一個函數進行調用操作,同時可以傳入一個數組作為調用參數。和 Function.prototype.apply() 功能類似。
Reflect.construct():對構造函數進行 new 操作,相當于執行 new target(...args)。
Reflect.defineProperty():和 Object.defineProperty() 類似。
Reflect.deleteProperty():作為函數的 delete 操作符,相當于執行 delete target[name]。
Reflect.enumerate():該方法會傳回一個包含有目标對象身上所有可枚舉的自身字元串屬性以及繼承字元串屬性的疊代器,for...in 操作周遊到的正是這些屬性。
Reflect.get():擷取對象身上某個屬性的值,類似于 target[name]。
Reflect.getOwnPropertyDescriptor():類似于 Object.getOwnPropertyDescriptor()。
Reflect.getPrototypeOf():類似于 Object.getPrototypeOf()。
Reflect.has():判斷一個對象是否存在某個屬性,和 in 運算符 的功能完全相同。
Reflect.isExtensible():類似于 Object.isExtensible().
Reflect.ownKeys():傳回一個包含所有自身屬性(不包含繼承屬性)的數組。(類似于 Object.keys(), 但不會受 enumerable 影響).
Reflect.preventExtensions():類似于 Object.preventExtensions()。傳回一個 Boolean。
Reflect.set():将值配置設定給屬性的函數。傳回一個 Boolean,如果更新成功,則傳回 true。
Reflect.setPrototypeOf():類似于 Object.setPrototypeOf()。
在此我們隻讨論 Reflect.ownKeys();
因為它類似于 Object.keys(),但是不受 enumerable 影響,所有它會傳回一個對象下面的所有屬性(不包括繼承屬性,但包括 Symbol 屬性);
// 我們對上述的obj,使用此方法,來周遊它的屬性
var objKeys_reflect = Reflect.ownKeys(obj);
console.log(objKeys_reflect); // ["c", "d", Symbol(a), Symbol(b)]
這樣就周遊了一個對象下的所有屬性了。
Symbol 的一個重要方法:Symbol.for();
在前面介紹 Symbol 在 ES6 的引入初衷時,我們提到了它是為了避免對象屬性被污染,而設計的一種新的資料類型。
Symbol 作為對象的屬性,優秀的解決了對象屬性被污染的問題,但是這樣還不夠。
因為我們有時候需要在某些地方重新使用已經定義的 Symbol,是以 Symbol();就不滿足不了這個需求了。
ES6 中就設計了 Symbol 的一個全局登記機制:使用 Symbol.for(key)方法會生成指定 key 的會被登記在全局環境中,在目前運作時具有全局有效性的 Symbol。同時,Symbol.keyFor 方法可以傳回一個已登記的 Symbol 類型值的 key。
// Symbol.for登記一個全局的Symbol
const symbol = Symbol.for('foobar');
Symbol.keyFor(symbol); // "foobar"
// Symbol.keyFor(),傳回一個已登記的 Symbol 類型值的key
var s1 = Symbol.for('foo');
Symbol.keyFor(s1); // "foo"
var s2 = Symbol('foo');
Symbol.keyFor(s2); // undefined
Symbol.for()與 Symbol()的差別:
Symbol.for()會根據傳入的 key 在全局作用域中注冊一個 Symbol 值,如果某個 key 值從未被注冊到全局作用域中,便會建立一個 Sybmol 值并根據 key 隻注冊到全局環境中。如果是該 key 已被注冊,就會傳回一個與第一次使用所建立的 Symbol 值等價的 Symbol 值。
const symbol = Symbol.for('foo');
const obj = {};
obj[symbol] = 'bar';
// ...
const anotherSymbol = Symbol.for('foo');
console.log(symbol === anotherSymbol); // true
console.log(obj[anotherSymbol]); // bar
這在大型的系統開發中可以用于一些全局的配置資料中或者用于需要多處使用的資料中。
各類型之間的轉換
String(value)、value.toString()、Boolean(value)、Number(value)、parseInt(value) 可以把對應的 value 轉化為相應的類型。
轉化為字元串
兩種方式将其他類型可以轉化為字元串,不過稍有差別。
String()方法
toString() 方法
1.使用 String():将其它對象轉化為字元串,可以被認為是一種更加安全的做法,雖然該方法底層使用的也是 toString() 方法,但是針對 null/undefined/symbols,String() 方法會有特殊的處理
// Number-->String
console.log(String(10)); // '10'
console.log(String(0)); // '0'
console.log(String(1)); // '1'
console.log(String(NaN)); // 'NaN'
// Boolean --> String
console.log(String(true)); // 'true'
console.log(String(false)); // 'false'
// Undefined --> String
console.log(String(undefined)); // 'undefined'
// Null --> String
console.log(String(null)); // 'null'
// Object-->String
console.log(String({a:1,b:"hello"})); // '[object Object]'
// String-->Symbol
console.log(String(Symbol('foo'));// 'Symbol(foo)'
2.使用 toString():會調用該類型下的 toString()方法,但是對于 Undefined、Null 類型的會抛出異常。對于 Object 類型的會傳回該對象的原始字元串表示:'[object,Object]',與 JSON.stringify(),傳回結果有别。
Number 使用 toString(),有兩種模式:
1.預設模式 toString()
2.基模式 toString(radix),隻對于 Number 有效
采用預設模式:直接使用 toString() 方法會輸出的字元串型的數字值(無論是整數、浮點數還是科學計數法)
// 預設模式
var iNum1 = 10,
iNum2 = 10.0,
iNum3 = 10.12;
console.log(iNum1.toString()); //輸出 "10"
console.log(iNum2.toString()); //輸出 "10"
console.log(iNum3.toString()); //輸出 "10.12"
采用基模式:使用 toString(radix) 可以指定傳入不同的基數 radix 輸出該數字對應基數的字元串型,例如二進制的基是 2,八進制的基是 8,十進制的基是 10,十六進制的基是 16。radix 範圍 2 ~ 36 之間的整數,超出傳回抛出異常, 預設模式是基數為 10 的基模式,預設可以不傳入參數。
// 基模式
var iNum = 10;
console.log(iNum.toString(2)); //輸出 "1010"
console.log(iNum.toString(8)); //輸出 "12"
console.log(iNum.toString(10)); //輸出 "10" 等價于:iNum.toString();
console.log(iNum.toString(16)); //輸出 "A"
// 基數超出範圍,抛出異常
console.log(iNum.toString(0)); // Uncaught RangeError: toString() radix argument must be between 2 and 36
console.log(iNum.toString(1)); // Uncaught RangeError: toString() radix argument must be between 2 and 36
console.log(iNum.toString(37)); // Uncaught RangeError: toString() radix argument must be between 2 and 36
// NaN使用基模式指定基數無效,結果傳回'NaN'
console.log(NaN.toString(2)); //輸出 "NaN"
console.log(NaN.toString(8)); //輸出 "NaN"
console.log(NaN.toString(10)); //輸出 "NaN"
console.log(NaN.toString(16)); //輸出 "NaN"
對于常量,數字.toString(),數字為整數時,會報錯,因為預設會把後面的.解析成整數的一部分,小數.toString()則正常,我們使用數字..toString()、(數字).toString()則輸出正常,一般使用後者,即可解決該問題;
對于變量則不會有上述問題。
console.log(10.toString()); // Uncaught SyntaxError: Invalid or unexpected token
console.log(10.67867.toString()); // '10.67867' 小數.toString(),不報錯
console.log(10.67867..toString()); // Uncaught SyntaxError: Unexpected token '.'
console.log(10..toString()); // '10' 雖然同樣可以輸出結果,一般不使用,以免引起不可控異常
// 一般使用(數字).toString()的寫法,避免.解析引起的異常
console.log((10).toString()); // '10'
console.log((10.67867).toString()); // '10.67867'
Boolean 使用 toString(),等價于 String()
console.log(true.toString()); // 'true'
console.log(false.toString()); // 'false'
Null、Undefined 使用 toString(),會抛出異常,與 String()有差別
console.log(null.toString()); // Uncaught TypeError: Cannot read property 'toString' of null
console.log(undefined.toString()); // Uncaught TypeError: Cannot read property 'toString' of undefined
Object 使用 toString(),等效于 String()
console.log({ a: 1, b: 'hello' }.toString()); // '[object Object]'
Symbol 使用 toString(),等效于 String()
console.log(Symbol('foo').toString()); // 'Symbol(foo)'
轉換為 Number
ECMAScript 提供了兩種把非數字的原始值轉換成數字的方法,即 parseInt() 和 parseFloat()。
前者把值轉換成整數,後者把值轉換成浮點數。隻有對 String 類型調用這些方法,它們才能正确運作;對其他類型傳回的都是 NaN。
當然作為 JS 的全局對象 Number(value),也可以把對象的值轉換為數字。
常用方法:
Number();
parseInt();
parseFloat();
Number():把對象的值轉換為數字,對于非數字字元串會特殊處理,與後兩種方法有别。
// Number(value)
console.log(Number('a')); // NaN
console.log(Number('10')); // 10
console.log(Number('')); // 0
console.log(Number('0')); // 0
console.log(Number('1')); // 1
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(undefined)); // NaN
console.log(Number(null)); // 0
console.log(Number({ a: 1, b: 'hello' })); // NaN
console.log(Number(Symbol('foo'))); // Uncaught TypeError: Cannot convert a Symbol value to a number
parseInt(string, [radix]):可解析一個字元串,并傳回一個整數。
radix 表示要解析的數字的基數。該值介于 2 ~ 36 之間。
傳入該值按照指定的基數解析,為 0 或不傳入會根據 string 來判斷數字的基數
如果它以 “0x” 或 “0X” 開頭,将以 16 為基數。
如果該參數小于 2 或者大于 36,則 parseInt() 将傳回 NaN。
舉例,如果 string 以 "0x" 開頭,parseInt() 會把 string 的其餘部分解析為十六進制的整數。
如果 string 以 0 開頭,那麼 ECMAScript v3 允許 parseInt() 的一個實作把其後的字元解析為八進制或十六進制的數字。
如果 string 以 1 ~ 9 的數字開頭,parseInt() 将把它解析為十進制的整數。
如果字元串的第一個字元不能被轉換為數字,那麼 parseFloat() 會傳回 NaN。
如果中間出現不能解析為數字的,會停止解析,傳回已解析的結果。
首尾出現空格會自動忽略。
正常解析為數值:
console.log(parseInt('0')); // 0
console.log(parseInt('1')); // 1
console.log(parseInt('10')); // 10
console.log(parseInt('010')); // 10 或 8 按照10進制或者是8進制解析,結果不定,但是控制台一般都是輸出10;
console.log(parseInt('0xa')); // 10 按照16進制解析,16^0*10 =10;
console.log(parseInt('0Xa')); // 10 按照16進制解析,16^0*10 =10;
console.log(parseInt('0xf')); // 15 按照16進制解析,16^0*15 =15;
console.log(parseInt('0x0f')); // 15 按照16進制解析,16^0*15 =15;
console.log(parseInt('0x1f')); // 31 按照16進制解析 16^11 + 16^015 =31;
console.log(parseInt('0xef')); // 239 按照16進制解析 16^114 + 16^015 =239;
指定基數正常解析:
console.log(parseInt('10', 2)); // 2 按照2進制解析,按照8421碼的速讀,為2;
console.log(parseInt('010', 2)); // 2 按照2進制解析,忽略0;
console.log(parseInt('1100', 2)); // 12 按照2進制解析,按照8421碼的速讀,為8+4=12;
console.log(parseInt('11', 2)); // 3 按照2進制解析,按照8421碼的速讀,為2+1=3;
console.log(parseInt('11111', 2)); // 31 按照2進制解析,2^41 + 2^31 + 2^21 + 2^11 + 2^0*1=31;
console.log(parseInt('10', 8)); // 8 按照8進制解析,8^11 + 8^00 =8;
console.log(parseInt('010', 8)); // 8 按照8進制解析,忽略進制辨別符0,8^11 + 8^00 =8;
console.log(parseInt('199', 10)); // 199 按照10進制解析;
console.log(parseInt('0199', 10)); // 199 按照10進制解析,忽略0;
console.log(parseInt('a', 16)); // 10 按照16進制解析,16^0*10 =10;
console.log(parseInt('0xa', 16)); // 10 按照16進制解析,忽略進制辨別符0x,16^0*10 =10;
超出基數解析:
console.log(parseInt('10', 0)); // 10 按照10進制解析;
console.log(parseInt('010', 0)); // 10 按照10進制解析;
console.log(parseInt('10', 1)); // NaN
console.log(parseInt('010', 1)); // NaN
console.log(parseInt('10', 68)); // NaN
console.log(parseInt('010', 68)); // NaN
特殊值解析:
console.log(parseInt('a')); // NaN
console.log(parseInt('')); // NaN
console.log(parseInt(true)); // NaN
console.log(parseInt(false)); // NaN
console.log(parseInt(undefined)); // NaN
console.log(parseInt(null)); // NaN
console.log(parseInt({ a: 1, b: 'hello' })); // NaN
console.log(parseInt(Symbol('foo'))); // Uncaught TypeError: Cannot convert a Symbol value to a number
首尾空格解析:
console.log(parseInt(' 10')); // 10
console.log(parseInt('10 ')); // 10
console.log(parseInt(' 10 ')); // 10
遇阻解析:
console.log(parseInt('a10')); // NaN
console.log(parseInt('1a0')); // 1
console.log(parseInt('10a')); // 10
parseFloat():将它的字元串參數解析成為浮點數并傳回。如果在解析過程中遇到了正負号(+ 或 -)、數字 (0-9)、小數點,或者科學記數法中的指數(e 或 E)以外的字元,則它會忽略該字元以及之後的所有字元,傳回目前已經解析到的浮點數。同時參數字元串首位的空白符會被忽略。
如果參數字元串的第一個字元不能被解析成為數字,則 parseFloat 傳回 NaN。
// parseFloat()
console.log(parseFloat('10.322')); // 10.322
console.log(parseFloat('0')); // 0
console.log(parseFloat('0x1')); // 0
console.log(parseFloat('0xf')); // 0
console.log(parseFloat(Math.PI)); // 3.141592653589793
console.log(parseFloat('a')); // NaN
console.log(parseFloat('')); // NaN
console.log(parseFloat(true)); // 1
console.log(parseFloat(false)); // 0
console.log(parseFloat(undefined)); // NaN
console.log(parseFloat(null)); // NaN
console.log(parseFloat({ a: 1, b: 'hello' })); // NaN
console.log(parseFloat(Symbol('foo'))); // Uncaught TypeError: Cannot convert a Symbol value to a number
轉換為 Boolean
一般使用 JS 全局對象 Boolean(),可以把指定類型轉換為 Boolean 型。
// Boolean(value)
console.log(Boolean('a')); // true
console.log(Boolean('')); // false
console.log(Boolean('10')); // true
console.log(Boolean(10)); // true
console.log(Boolean(0)); // false
console.log(Boolean(1)); // true
var a;
console.log(Boolean(a)); // false
console.log(Boolean(null)); // false
console.log(Boolean({ a: 1, b: 'hello' })); // true
console.log(Boolean(Symbol('foo'))); // true
同樣的,取反運算符!、!!也可以把特定類型的轉換為 Boolean 型。
console.log(!''); // true
console.log(!!''); // false
console.log(!'a'); // false
console.log(!!'a'); // true
console.log(!0); // true
console.log(!!0); // false
console.log(!!1); // true
console.log(!1); // false
console.log(!undefined); // true
console.log(!!undefined); // false
console.log(!null); // true
console.log(!!null); // false
console.log(!{ a: 1, b: 'hello' }); // false
console.log(!!{ a: 1, b: 'hello' }); // true
console.log(!Symbol('foo')); // false
console.log(!!Symbol('foo')); // true
關于各類型之間的隐式轉換
上述的類型轉換都是我們主動轉換的,屬于顯式轉換,但是在 js 的運算中,當運算符在運算時,如果兩邊資料不統一,CPU 就無法計算,這時我們編譯器會自動将運算符兩邊的資料做一個資料類型轉換,轉成一樣的資料類型再計算,這種無需程式員手動轉換,而由編譯器自動轉換的方式就稱為隐式轉換。
常見的隐式轉換:
字元串連接配接
比較運算
算術運算
特殊表達式
字元串連接配接:連接配接之前會将非字元串轉換為字元串,再做連接配接運算(Symbol 值除外,會抛出異常);
console.log('a' + 10); // 'a10'
console.log('a' + 0); // 'a0'
console.log('a' + 1); // 'a1'
console.log('a' + NaN); // 'aNaN'
console.log('a' + true); // 'atrue'
console.log('a' + false); // 'afalse'
console.log('a' + undefined); // 'aundefined'
console.log('a' + null); // 'anull'
console.log('a' + { a: 1, b: 'foo' }); // 'a[object Object]'
console.log('a' + Symbol('foo')); // Uncaught TypeError: Cannot convert a Symbol value to a string
比較運算:'>'、'<' 、'==',會調用 Number()方法,轉換數值後再做比較。
'==='不會隐式轉換類型,同時比較數值與其類型。
特列:
字元串直接的大小比較:從首位逐個對比其對應的 Unicode 編碼值的大小;
可以使用 charCodeAt()擷取字元串中某個字元的 Unicode 值
null=null 為 true,任何兩個 null 都是相等的
NaN=NaN 為 false,任何兩個 NaN 都是不相等的
undefined==null 為 true
console.log('a' > 'b'); // false 比較Unicode值,97>98
console.log('a' < 10); // false
console.log('a' == 10); // false
console.log('a' === 10); // false
console.log('5' > '10'); // true 按照字元串比較來判斷
console.log('10' > 10); // fasle
console.log('10' < 10); // fasle
console.log('10' == 10); // true
console.log('10' === 10); // false
// 特殊比較
console.log(null === null); // true
console.log(undefined === undefined); //true
console.log(NaN == NaN); //false
console.log(NaN === NaN); //false
console.log(undefined == null); // true
console.log(undefined === null); // false
console.log(NaN == undefined); //false
console.log(NaN == null); // false
算術運算:會隐式的使用 Number()轉換為數值型後,再做運算。
特例:
非數字的字元串與數值型數字相加,不會使用此規則,會使用字元串連接配接規則;
Object 與數字相加,不會使用此規則,會使用字元串連接配接規則;
數組與數字相加,不會使用此規則,會使用字元串連接配接規則;
Symbol 值參與算術運算,會抛出異常。
// 加運算 +
console.log('a' + 10); // 'a10' 特例,直接使用字元串連接配接原則
console.log('10' + 10); // 20 10 + 10
console.log(true + 10); // 11 1 + 10
console.log(false + 10); // 10 0 + 10
console.log(undefined + 10); // NaN NaN + 10
console.log(null + 10); // 10 0 + 10
console.log({ a: 1, b: 'hello' } + 10); // '[object Object]10' 特例:使用了字元串連接配接原則
console.log(['a', 'b'] + 10); // 'a,b10' 特例:使用了字元串連接配接原則
console.log(Symbol('foo') + 10); // Uncaught TypeError: Cannot convert a Symbol value to a number
// 減運算 -
console.log('a' - 10); // NaN
console.log('10' - 10); // 0 10 - 10
console.log(true - 10); // -9 1 - 10
console.log(false - 10); // -10 0 - 10
console.log(a - 10); // NaN NaN - 10
console.log(null - 10); // -10 0 - 10
console.log({ a: 1, b: 'hello' } - 10); // NaN
console.log(['a', 'b'] - 10); // NaN
console.log(Symbol('foo') - 10); // Uncaught TypeError: Cannot convert a Symbol value to a number
// 除運算符 /
console.log('a' / 10); // NaN
console.log('10' / 10); // 1
console.log(true / 10); // 0.1
console.log(false / 10); // 0
console.log(undefined / 10); // NaN
console.log(null / 10); // 0
console.log({ a: 1, b: 'hello' } / 10); // NaN
console.log(['a', 'b'] / 10); // NaN
console.log(Symbol('foo') / 10); // Uncaught TypeError: Cannot convert a Symbol value to a number
// 取餘運算符 %
console.log('a' % 10); // NaN
console.log('10' % 10); // 0
console.log(true % 10); // 1
console.log(false % 10); // 0
console.log(undefined % 10); // NaN
console.log(null % 10); // 0
console.log({ a: 1, b: 'hello' } % 10); // NaN
console.log(['a', 'b'] % 10); // NaN
console.log(Symbol('foo') % 10); // Uncaught TypeError: Cannot convert a Symbol value to a number
// += -= /= %= 也是在上述規則上,做運算
特殊表達式: +字元串、-字元串、會把目前字元串轉換為 Number,等價于 Number(字元串),然後根據+/-對應取正負。
console.log();
console.log(+'a'); // NaN
console.log(+'10'); // 10
console.log(+true); // 1
console.log(+false); // 0
console.log(+undefined); // NaN
console.log(+null); // 0
console.log(+{ a: 1, b: 'hello' }); // NaN
console.log(+['a', 'b']); // NaN
console.log(+Symbol('foo')); // Uncaught TypeError: Cannot convert a Symbol value to a number
console.log(-'a'); // NaN
console.log(-'10'); // -10
console.log(-true); // -1
console.log(-false); // -0 與0等價:-false===0 為true
console.log(-undefined); // NaN
console.log(-null); // -0 與0等價: -null===0 為true
console.log(-{ a: 1, b: 'hello' }); // NaN
console.log(-['a', 'b']); // NaN
console.log(-Symbol('foo')); // Uncaught TypeError: Cannot convert a Symbol value to a number
總結:
JavaScript 主要有 7 種原始資料類型:
上述彙總了以上清單内容,資訊較多,如有纰漏,歡迎指點。
原文位址
https://www.cnblogs.com/wiwimi/p/12591696.html