不一樣的對象底層都表示爲二進制,其低位的 1-3 位用來存儲類型信息,typeof 就是經過判斷前三位的機器碼來斷定類型。斷定規則以下:api
有兩個值比較特殊:bash
null(JSVAL_NULL)markdown
null 的全部機器碼爲 0,所以 typeof null 爲"object"函數
undefined(JSVAL_VOID)oop
用整數 −2^30(整數範圍以外的數字)表示。post
如下是 typeof 的引擎代碼:spa
JS_PUBLIC_API(JSType)
JS_TypeOfValue(JSContext *cx, jsval v)
{
JSType type = JSTYPE_VOID;// 初始化爲undefined
JSObject *obj;
JSObjectOps *ops;
JSClass *clasp;
CHECK_REQUEST(cx);
if (JSVAL_IS_VOID(v)) {
type = JSTYPE_VOID;
} else if (JSVAL_IS_OBJECT(v)) {
obj = JSVAL_TO_OBJECT(v);
if (obj &&
(ops = obj->map->ops,
ops == &js_ObjectOps
? (clasp = OBJ_GET_CLASS(cx, obj),
clasp->call || clasp == &js_FunctionClass)
: ops->call != 0)) {
type = JSTYPE_FUNCTION;
} else {
type = JSTYPE_OBJECT;
}
} else if (JSVAL_IS_NUMBER(v)) {
type = JSTYPE_NUMBER;
} else if (JSVAL_IS_STRING(v)) {
type = JSTYPE_STRING;
} else if (JSVAL_IS_BOOLEAN(v)) {
type = JSTYPE_BOOLEAN;
}
return type;
}
複製代碼
能夠看到 typeof 首先判斷值是否是 undefined(經過值是否是等於 JSVAL_VOID(−2^30)來判斷)。prototype
#define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID) 複製代碼
當判斷爲 object 類型後會做進一步判斷,若是能夠調用 call 或者內部屬性[[Class]]標記爲函數則爲函數,所以 typeof 能夠判斷是否是函數。code
clasp->call
clasp == &js_FunctionClass
複製代碼
對於 null,經過 JSVAL_IS_OBJECT 判斷爲 true 後,做進一步判斷,不是函數,所以爲 object。orm
#define JSVAL_IS_OBJECT(v) (JSVAL_TAG(v) == JSVAL_OBJECT) 複製代碼
typeof 只能判斷基本類型,此外還有一個兼容性較好的判斷類型的方法,即 Objct.prototype.toString 方法,以下:
Object.prototype.toString.call('xhm') // "[object String]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
Object.prototype.toString.call({ name:'xhm' }) // "[object Object]"
Object.prototype.toString.call(['a', 'b']) // "[object Array]"
Object.prototype.toString.call(() => {}) // "[object Function]"
複製代碼
instanceof 的用途爲判斷對象 object 是否屬於某個類型,基本用法以下:
/*
object: 對象
constructor: 構造器
object instanceof constructor
*/
const Food = function() {};
const meat = new Food();
meat instanceof Food // true
複製代碼
由JS 中的繼承與原型鏈一文咱們能夠知道,當構造函數在執行時會將返回對象的 prototype 賦值給實例對象的__proto__
,所以能夠經過判斷實例對象或其原型鏈中的__proto__
是否等於構造函數的 prototype 來檢查對象的類型。其實現思路大體以下:
var newInstanceof = (obj, ctor) => {
let objProto = obj.__proto__;
while(objProto) {
if (objProto === ctor.prototype) {
return true;
}
objProto = objProto.__proto__;
}
return false;
}
newInstanceof(meat, Food) // true
複製代碼
來看下面的例子:
var Food = function() {};
var Meat = function() {};
Meat.prototype = new Food();
var meat = new Meat();
newInstanceof(meat, Meat) // true
newInstanceof(meat, Food) // true
meat instanceof Meat // true
meat instanceof Food // true
複製代碼
咱們看到 meat instanceof Food 爲 true,由於 meat 在原型鏈上可以找到 Food,來看另外一個例子:
var Meat = function() {
return { name: 'xhm' };
};
var meat = new Meat();
newInstanceof(meat, Meat); // false
meat instanceof Meat // false
複製代碼
咱們看到 meat instanceof Meat 爲 false,由於 instanceof 的本質是判斷原型鏈上的對象,而當一個對象不是經過原型構造出來的實例時(Meat 構造函數返回了一個與 Meat 絕不相干的對象),這種斷定方法就會失效。