深挖js中instanceof 和 typeof 的实现原理




ES6内置数据类型

  • 在es6标准中的JS 中,有七种内置类型

  • 七种内置类型又分为两大类型:基本类型和对象(Object)。

  • 基本类型有六种: nullundefinedbooleannumberstringsymbol

一些值得注意的坑

  • JS 的数字类型是浮点类型的,没有整型。并且浮点类型基于 IEEE 754标准实现,在使用中会遇到某些 Bug。

  • NaN 属于 number 类型,并且 NaN 不等于自身。

  • 对象(Object)是引用类型,在使用过程中会遇到浅拷贝和深拷贝的问题。

  • 对于基本类型来说,如果使用字面量的方式,那么这个变量只是个字面量,只有在必要的时候才会转换为对应的类型

let a = 111 // 这只是字面量,不是 number 类型
a.toString() // 使用时候才会转换为对象类型
typeof a  // 需要时就会转换为对应的类型

typeof

用法

typeof 一般被用于判断一个变量的类型,我们可以利用 typeof 来判断number, string,object, boolean, function, undefined, symbol 这七种类型。

  • 输出值:number,boolean,string,function(函数),object(NULL,数组,对象),undefined,symbol

  • typeof 对于基本类型,除了 null 都可以显示正确的类型

  • 使用形式:typeof x 或者 typeof(x)。

注意点

  • null 返回 “object” —— 这是js中的一个坑,实际上它并不是一个对象

  • 一般object建议用instanceof来判断类型

原理

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息,如下所示

  • 000:对象
  • 010:浮点数
  • 100:字符串
  • 110:布尔
  • 1:整数

null:所有机器码均为0

undefined:用 −2^30 整数来表示

js的typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待,这是自js诞生以来就一直留下的一个坑。

一些例子

// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写
typeof Number(1) === 'number'; // 但不要使用这种形式!

// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof总是返回一个字符串
typeof String("abc") === 'string'; // 但不要使用这种形式!

// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 但不要使用这种形式!

// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';

// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined'; 

// Objects
typeof {a:1} === 'object';

// 使用Array.isArray 或者 Object.prototype.toString.call
// 区分数组,普通对象
typeof [1, 2, 4] === 'object';

typeof new Date() === 'object';

// 下面的容易令人迷惑,不要使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) ==== 'object';
typeof new String("abc") === 'object';

// 函数
typeof function(){} === 'function';
typeof Math.sin === 'function';

//NaN
typeof 1/0 === 'NaN';

自己实现一个?

由于涉及到底层一些存储的东西。具体怎么说实现我也不太了解。




instanceof

instanceof 运算符是用来在运行时指出对象是否是构造器的一个实例, 例如漏写了new运算符去调用某个构造器, 此时构造器内部可以通过 instanceof 来判断。

用法

是否在原型链上

obj instanceof Object 检测Object.prototype是否存在于参数obj的原型链上

function Person(){};
var p = new Person();
console.log(p instanceof Person);//true
继承中判断实例是否属于它的父类或属于它的祖先类

Student和Person都在s的原型链中

function Person(){};
function Student(){};
var p = new Person();
Student.prototype= p; 
console.log(s instanceof Student);//true
console.log(s instanceof Person);//true


原理

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

function Foo(){};
var f1 = new Foo();
console.log(f1 instanceof Foo);//true
// Foo.prototype在f1.__proto__到Object.prototype这条原型链上吗?

img

function Person() {}
console.log(Object instanceof Object);     //true
//第一个Object的原型链:Object=>
//Object.__proto__ => Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个Object的原型:Object=> Object.prototype

console.log(Function instanceof Function); //true
//第一个Function的原型链:Function=>Function.__proto__ => Function.prototype
//第二个Function的原型:Function=>Function.prototype

console.log(Function instanceof Object);   //true
//Function=>
//Function.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//Object => Object.prototype

console.log(Person instanceof Function);      //true
//Person=>Person.__proto__=>Function.prototype
//Function=>Function.prototype

console.log(String instanceof String);   //false
//第一个String的原型链:String=>
//String.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个String的原型链:String=>String.prototype

console.log(Boolean instanceof Boolean); //false
//第一个Boolean的原型链:Boolean=>
//Boolean.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个Boolean的原型链:Boolean=>Boolean.prototype

console.log(Person instanceof Person); //false
//第一个Person的原型链:Person=>
//Person.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个Person的原型链:Person=>Person.prototype

自己实现一个?

思路很简单,就是相当于一个链表的遍历。

right instanceof left

重点就在于right.prototype在left.__proto__到Object.prototype这条原型链上吗?

function _instanceof(left, right) {
    // 获得类型的显型原型
    let prototype = right.prototype
    
    // 获得对象的隐型原型
    left = left.__proto__
    
    // 判断对象的类型是否等于类型的原型
    //  
    while (true) {
        // Object.prototype.__proto__ === null
    	if (left === null)
    		return false
    	if (prototype === left)
    		return true
    	left = left.__proto__
    }
}

img


总结

typeof用于判断基本类型,instanceof 用于判断具体对象类型。

参考资料

《浅谈 instanceof 和 typeof 的实现原理》

《JS原型链与继承别再被问倒了》

JavaScript中typeof详解

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值