typeof 原理
在javascript中,我们判断一个变量的类型经常用的是typeof来判断number, string, object, boolean, function, undefined, symbol(es6新增数据类型,我还没用到过) 这七种类型;在判断基本数据类型的时候,能告诉我们具体是哪种类型,但是在判断引用类型的时候,比如object,不能确定的告诉我们具体是哪种数据类型,如:
function Person() {
}
var p = new Person();
console.log(typeof p === 'object'); //true
console.log(p instanceof Person); //true
在用typeof判断的时候,只会告诉我们是object,而不会告诉我们具体是哪种object,有一个特例就是 typeof null === ''object'' 返回true ;所以在判断具体是哪种object类型的时候都是用instanceof 来判断,先说说typeof原理:
在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:
- 000:对象
- 1:整数
- 010:浮点数
- 100:字符串
- 110:布尔
有 2 个值比较特殊:
- undefined:用 - (−2^30)表示。
- null:对应机器码的 NULL 指针,一般是全零。
typeof null === 'object';
null instanceof Object === false
但是
null instanceof null // TypeError: Right-hand side of 'instanceof' is not an object
这是js历史遗留的一个bug 所以null也成为 "薛定谔的对象";
因此在用 typeof 来判断变量类型的时候,我们需要注意,最好是用 typeof 来判断基本数据类型(包括symbol),避免对 null 的判断;
instanceof 原理
在MDN官方文档中是这样介绍的
instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype不在o的原型链上
o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为C.prototype现在在o3的原型链上
根据instanceof的检测原理,我们可以实现一个自定义的myInstanceof
function Person() {
}
var p = new Person();
function myInstanceof(l, r) {
let rValue = r.prototype; // 取右表达式的 prototype 值
let lValue = l.__proto__; // 取左表达式的__proto__值
//对待检测的对象原型进行遍历
while (true) {
if (lValue === null) {
return false;
}
if (lValue === rValue) {
return true;
}
lValue = lValue.__proto__;
}
}
console.log(myInstanceof(p,Person)); //true
console.log(myInstanceof(p,Object)); //true console.log(myInstanceof(p,Array)); //false
还有一个不错的判断类型的方法,就是Object.prototype.toString,我们可以利用这个方法来对一个变量的类型来进行比较准确的判断
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('helloworld') // "[object String]"
Object.prototype.toString.call({a:'hello world'}) // "[object Object]"
Object.prototype.toString.call([1,'a',false]) // "[object Array]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(() => {}) // "[object Function]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
这里我将这个方法封装成一个函数,可参考使用:
var isType = (function () {
var types = {};
var t = ['Array','String','Number'];
for(var i = 0;i<t.length;i++){
(function (type) {
types['is'+type] = function (obj) {
return Object.prototype.toString.call(obj) === '[object '+type+']';
}
})(t[i])
}
return types;
})();
isType.isArray([]); //true