typeof和instanceof实现原理
typeof
不同的对象底层都表示为二进制,其低位的 1-3 位用来存储类型信息,typeof 就是通过判断前三位的机器码来判定类型。判定规则如下:
- 000: 对象
- 110: 布尔
- 010: 浮点数
- 100: 字符串
- 1: 整数
有两个值比较特殊:
-
null(JSVAL_NULL)
null 的所有机器码为 0,因此 typeof null 为"object"
-
undefined(JSVAL_VOID)
用整数 −2^30(整数范围之外的数字)表示。
以下是 typeof 的引擎代码:
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)来判断)。
#define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID)
当判断为 object 类型后会作进一步判断,如果可以调用 call 或者内部属性[[Class]]标记为函数则为函数,因此 typeof 可以判断是不是函数。
clasp->call
clasp == &js_FunctionClass
对于 null,通过 JSVAL_IS_OBJECT 判断为 true 后,作进一步判断,不是函数,因此为 object。
#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
instanceof 的用途为判断对象 object 是否属于某个类型,基本用法如下:
/*
object: 对象
constructor: 构造器
object instanceof constructor
*/
const Food = function() {};
const meat = new Food();
meat instanceof Food // true
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 毫不相干的对象),这种判定方法就会失效。
转载自:https://juejin.cn/post/6844903850395058190