一、JS中的數據類型
基本類型
分為以下六種:
- string(字符串)
- boolean(布爾值)
- number(數字)
- symbol(符號)
- null(空值)
- undefined(未定義)
說明:
-
symbol是ES6中新增的數據類型,symbol 表示獨一無二的值,通過 Symbol 函數調用生成,由於生成的 symbol 值為原始類型,所以 Symbol 函數不能使用 new 調用;
-
null 和 undefined 通常被認為是特殊值,這兩種類型的值唯一,就是其本身
-
簡單數據類型不可以有自定義屬性和方法的,但string/number/boolean卻有對應的包裝類型String/Number/Boolean,
var str = 'hello';
str.substr(0,1); // h
// 執行到這一句,后台依然會偷偷的干這些事
{
var _str = new String('hello'); // 找到基本包裝對象,new一個和字符串值相同的對象
_str.substr(0,1); // 通過這個對象找到了包裝對象下的方法並調用,輸出結果
_str =null; //釋放這個對象
}
特別注意boolean類型的計算:
console.log(new Boolean(false) && true) //true
console.log(Boolean(false) && true) //false
console.log(false && true) //false
console.log(1 + true) // 2
console.log('1' + true) // 1true
console.log(1 + '2' + true) //12true
對象類型
對象類型也叫引用類型,array和function是對象的子類型。對象在邏輯上是屬性的無序集合,是存放各種值的容器。對象值存儲的是引用地址,對象值是可變的。
每個對象都有一個 toString() 方法和一個valueOf()方法
Object.prototype.toString()
當對象被表示為文本值時或者當以期望字符串的方式引用對象時,該方法被自動調用。
Object.prototype.valueOf()
當把對象轉換成原始類型的值時(如強制轉換和運算)會自行調用。
var temp = function() {
}
temp.valueOf = function() {
return 2;
}
temp.toString = function() {
return 'hello';
}
console.log(temp); //hello
console.log(2 * temp); //4
二、JS類型轉換
弱類型
JavaScript 是弱類型語言,JavaScript 聲明變量時並沒有預先確定類型,變量的類型由其值所決定,由於這種“不需要預先確定類型”特性給我們帶來了便利,同時帶來了類型轉換的復雜度。例如:
String({}) // '[object Object]'
String([1,[2,3]]) // 1,2,3
強制轉換規則
1、內部函數:toPrimitive(input,preferedType?)
input是輸入的值,preferedType是期望轉換的類型,它可以是字符串,也可以是數字。
- 如果轉換的類型是number,會執行以下步驟:
-
如果input是原始值,直接返回這個值;
-
否則,如果input是對象,調用input.valueOf(),如果結果是原始值,返回結果;
-
否則,調用input.toString()。如果結果是原始值,返回結果;
-
否則,拋出錯誤。
-
如果轉換的類型是String,2和3會交換執行,即先執行toString()方法。
-
省略preferedType參數,此時日期會被認為是字符串,而其他的值會被當做Number
2、強制轉換函數:String()、Number() 、Boolean()
String 轉換規則
String(null) //"null"
String(undefined) //"undefined"
String(true) //"true"
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(1E+400) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,[3,4]],['a']) // '1,2,3,4,a'
String(function (){return 0}) //function({return 0})
注意:
- 數字轉換遵循通用規則,溢出將以指數形式或者無窮大
- 數組的toString()方法會返回一個以逗號分割的字符串,不論嵌套的層次
- 函數的toString()方法返回函數本身
- 對象的toString()方法返回"[object Object]",前一個object標記基礎類型,后一個Object標記子類型
Number轉換規則:
Number(null); //0
Number(undefined); //NaN
Number(true); //1
Number(false); //0
Number('1'); //1
Number('a'); //NaN
注意:
- undefined 轉換為 NaN
- 字符串轉換時遵循數字常量規則,轉換失敗返回 NaN
Boolean轉換規則
除了下述5 個值轉換結果為 false,其他全部為 true
- undefined
- null
- 0、+0、-0
- NaN
- ''(空字符串)
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
注意:
- new Boolean(false)也是true
自動轉換規則
1、什么時候自動轉換為string
- 字符串的自動轉換,主要發生在字符串的加法運算時。當一個值為字符串,另一個值為非字符串,則后者轉為字符串。
'2' + 1 // '21'
'2' + true // "2true"
'2' + undefined // "2undefined"
null + '2' // "null2"
'2' + function (){} // "2function (){}"
['test',1] + '2' // test,12
var obj = {
toString:function(){
return 'a'
}
}
console.log(obj+'2') //a2
2、什么時候自動轉換為Number類型
-
在有加法運算符但是無String類型的時候,都會優先轉換為Number類型
true + 0 // 1 true + true // 2 true + null //1 true + undefined //NaN
-
除了加法運算符,其他運算符轉換為Number類型
'5' - '2' // 3 '5' * '2' // 10 false - 1 // -1 '5' * [] // 0 false / '5' // 0 'abc' - 1 // NaN null + 1 // 1 undefined + 1 // NaN +'abc' // NaN +true // 1
-
雙等號==即抽象相等,會優先轉換Number進行比較
var obj1 = {
valueOf:function(){
return '1'
}
}
1 == obj1 //true
[] == ![] //true
//[]作為對象ToPrimitive得到 ''
//![]作為boolean轉換得到0
//'' == 0
//轉換為 0==0 //true
3 == true // false
'0' == false //true
//存在boolean,會將boolean轉換為1或者0
NaN == NaN // false
{} == {} // false
'2' == 2 // true
'a' == 'a' // true
//對於ToPrimitive為Number得到NaN后會判斷原始類型是不是string
//如果相等返回ture,否則NaN的比較返回false
什么時候轉換Boolean類型
- 使用否定運算符
- if() , while()、三元運算符判斷時
三、js中的數據類型判斷
typeof
typeof 'hello' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 無法判定是否為 null
typeof undefined // 'undefined'
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
注意:
-
null 的判定有誤差,得到的結果是object,原因是在第一代javascipt設計中,數值是以32字節存儲的,由標志位(1~3個字節)和數值組成。其中000標志為對象,所以
Object.prototype.__proto__
的值為null,反推是typeof null
的值為object, -
數組得到的結果是object
instanceof
通過 instanceof 操作符也可以對對象類型進行判定,其原理就是測試構造函數的 prototype 是否出現在被檢測對象的原型鏈上。
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
但是instanceof 也不是萬能的。 在數組上依舊存在誤區,原因是 Array.prototype.**proto** === Object.prototype
let arr = []
arr instanceof Array // true
arr instanceof Object // true
Object.prototype.toString()
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('hello') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(JSON) // '[object JSON]'
Object.prototype.toString.call(new Set()) // '[object Set]'
function Person() {}
var person = new Person();
Object.prototype.toString.call(person); // "[object Object]"
我可以發現該方法在傳入任何類型的值都能返回對應准確的對象類型。雖然簡單明了,但需要注意以下幾點:
- Object.prototype.toString()本身是允許被修改的,所以Object.prototype.toString()這個方法的應用都是假設toString()方法未被修改為前提的。
- 只有原生的js會返回內部屬性[class],其余自定義的對象返回Object
四、其他注意點
NaN 的問題
NaN 是一個全局對象的屬性,是一種特殊的Number類型。返回NaN的情況:
-
無窮大除以無窮大
-
給任意負數做開方運算
-
算數運算符與不是數字或無法轉換為數字的操作數一起使用
-
字符串解析成數字
Infinity / Infinity; // 無窮大除以無窮大
Math.sqrt(-1); // 給任意負數做開方運算
'a' - 1; // 算數運算符與不是數字或無法轉換為數字的操作數一起使用
undefined + 1 // NaN
parseInt('a'); // 字符串解析成數字
+'abc' // NaN
toString()和String()的區別
-
toString()可以將數據都轉為字符串,但是null和undefined不可以轉換。
console.log(null.toString()) //報錯 TypeError: Cannot read property 'toString' of null console.log(undefined.toString()) //報錯 TypeError: Cannot read property 'toString' of undefined
-
toString()括號中可以寫數字,代表進制
(18).toString(2); //'10010'