JS專題之數據類型和類型檢測

本文共 1750 字,讀完只需 7 分鐘

數據類型有哪些?

ECMAScript 的數據類型分爲簡單數據類型(也被稱爲基本數據類型,原始數據類型):

  1. Undefined
  2. Null
  3. String
  4. Number
  5. Boolean

在 ES6 中新增一個簡單數據類型 Symbol,所以簡單數據類型總共有 6 個,還有複雜數據類型(也叫作引用數據類型):Object。

所有 js 中所有的值最終都將是以上 7 種數據類型之一。

基本數據類型

基本數據類型是保存在的數據結構中的,是按值訪問的,基本數據類型的值不會變 (值本身無法被改變)
數據之間進行的是它們的比較。
看代碼:

var a,b;
a = "jay_chou";
b = a;
console.log(a);  // jay_chou
console.log(b);  // jay_chou
a = "coldplay";  // 改變 a 的值,並不影響 b 的值
console.log(a);   // coldplay
console.log(b);  // jay_chou

引用數據類型

除了基本的數據類型外,剩下的就是引用類型,統稱爲 Object 類型, 細分的話,有 Object 類型,Array 類型,Date 類型, Regexp 類型,function, Math 類型;

引用數據類型的特點:

  • 引用數據類型的值保存的是對象在內存中的地址
  • 引用數據類型的值是可變的
  • 引用數據類型的比較是引用的比較
  • 另外:js 不能直接操作對象的內存空間

比方:

var a = {
    name: "jay_chou"
}

var b = a;

var c = {
    name: "jay_chou"
}

a === b; // true
a === c; // false

一、爲什麼要進行類型檢測?

JavaScript 是動態語言,動態語言和靜態語言的區別在於:類型是在編譯時檢查(靜態)還是在運行時檢查(動態)。

基於動態類型的特點,如果不注意進行類型檢測,JS 很容易在運行代碼發生才發現報錯。

舉個列子:
函數在定義時,參數可以是任何類型,但是函數在實際運行的時候,傳入的實參可能是其他同事函數的返回值,也可能是後臺的返回值,假如不符合代碼邏輯裏要求的數據類型,那麼就會報錯導致 bug 影響程序運行。

因此,我們不光要做類型檢測,也應該給自己的函數註釋好參數類型和返回值類型,還要和後端定義好接口數據類型格式。

當比較的兩個值的類型不同的時候 == 運算符會進行類型轉換,但是當兩個值的類型相同的時候,即使是 == 也相當於是 ===;=== 在比較兩個值的時候,還會比較值的數據類型。

二、typeof 方式

typeof 的返回值總是字符串,字符串的可能值有:

  1. undefined
  2. boolean
  3. number
  4. string
  5. symbol
  6. object
  7. function

typeof 其實是一元操作符,和 + - * / 一樣,不是一個函數,進行比較的時候,typeof 後面可以跟(), 也可以不跟。

undefined:

typeof undefined; // undefined

很多庫因爲考慮到 undefined 可能會被意外重寫,用 void 0 來判斷是否是 undefined。

var isUndefined = function (obj) {
    return obj === void 0;
}

MDN 上對 void 詞條的說明是:

The void operator evaluates the given expression and then returns undefined.

意思是說 void 運算符能對給定的表達式進行求值,然後返回 undefined。也就是說,void 後面你隨便跟上一個表達式,返回的都是 undefined,都能完美代替 undefined。

string, number, boolean, symbol, function, object :

typeof "abc"; // string

typeof 123; // number

typeof NaN; // number

typeof true; // boolean

typeof Symbol(); // symbol

typeof function () {}; // function

typeof {}; // object

null

typeof null; // object!!!

js 中,不同的對象在底層都表示爲二進制,在Javascript中二進制前三位都爲 0 的話會被檢測爲 Object 類型,null 的二進制表示全爲0,自然前三位也是 0,所以執行 typeof 時會返回 "object"。

Array, Date, Regexp, Math:

typeof []; // object

數組的判斷不考慮兼容性的話,可以用 Array.isArray() 方法進行檢測。

typeof new Date(); // object

typeof /s/g; // object

typeof Math; // object

typeof new String("foo"); // object!!!

typeof new Number(123); // object!!!

typeof new Boolean(true); // object!!!

typeof new Function(""); // function

typeof new Error(); // object

基於以上,基本類型大部分都能被準確檢測並返回正確的字符串,並不是所有的類型都能被正確檢測出來。所以在實際應用中,避免用基本包裝類型 new Number() 這種方式來初始化數據。

三、instanceof 方式

上面說到基本包裝類型:new Number(), new Boolean, New String();

它們用 typeof 判斷,會檢測成對象。那針對基本包裝類型可以用 instanceof 來判斷。

instanceof 運算符可以用來檢測某個構造函數的 prototype 屬性是否存在於另外一個要檢測對象的原型鏈上。

// 定義構造函數
function Person(){} 

var person1 = new Person();

// 因爲 Object.getPrototypeOf(person1) === Person.prototype
person1 instanceof Person;  // true

現在我們檢測一下:

var str = new String('abc');  // 基本包裝類型
var strValue = "foo";

strValue instanceof String;  // false
str instanceof String;  // true
str instanceof Object;  // true

[] instanceof Array;  // true
[] instanceof Object;  // true

如果我們修改構造函數的原型後,這個方法也不怎麼靠譜了:

var str = new String('abc');
str.__proto__ = Object.prototype;
str instanceof String;  // false !!!
str instanceof Object;  // true 

四、toString() 方式

ECMAScript 的 Boolean 值、數字和字符串的原始值的有趣之處在於它們是僞對象,這意味着它們實際上具有屬性和方法。

ECMAScript 定義所有對象都有 toString() 方法,無論它是僞對象,還是真對象。因爲 String 類型屬於僞對象,所以它一定有 toString() 方法。

使用 Object.prototype.toString 方法, 可以獲取到變量的準確的數據類型.

Object.prototype.toString.call(1);  // '[object Number]'
Object.prototype.toString.call('1');  // '[object String]'
Object.prototype.toString.call(NaN);  // '[object Number]'
Object.prototype.toString.call(foo);  // '[object Function]'
Object.prototype.toString.call(Symbol());  // "[object Symbol]"
Object.prototype.toString.call([1,2,3]);  // '[object Array]'
Object.prototype.toString.call(undefined);  // '[object Undefined]'
Object.prototype.toString.call(null);  // '[object Null]'
Object.prototype.toString.call(true);  // '[object Boolean]'
Object.prototype.toString.call(/^s/g);  // '[object RegExp]'
Object.prototype.toString.call(Math);  // "[object Math]"
Object.prototype.toString.call(new Error());  // "[object Error]"
Object.prototype.toString.call(new Date());  // "[object Date]"

toString 就能解決基本包裝類型的檢測錯誤和 instanceof 的檢測不安全。

基於 toString 我們可以構造很多工具函數用來檢測數據類型,這一塊實現的方案很多,本文就按下不表。

五、應用場景

js 類型檢測常見的應用場景:
應用場景:添加默認值

function foo(a, b) {
    // 方式一
    if (typeof b=== 'undefined') {
      b = 0;
    }

    // 方式二:不適用foo(10, false)這種情況
    b = b || 0;
}
foo(10);

回調函數調用

function fn(callback) {
    //typeof callback === 'function' ? callback() : null;
    callback && callback();
}
fn(function () {
    
});

還有一個很常見的應用場景當然是後臺返回數據的類型的檢測了。

總結

js 是動態語言,數據類型的檢查是在運行時執行,爲了避免代碼莫名其妙報錯,所以做好數據類型的檢測很有必要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章