typeof 和 instanceof 实现原理
1.typeof
1.基本使用
typeof 返回的是变量的基本类型。JavaScript 中包括基本数据类型和引用类型,通常用于对变量所持有的值的判断,使用 typeof
,结果可能是 8 种:
number
、string
、object
、boolean
、symbol
、function
、undefined
、bigInt
。
2.实现原理:
typeof
是通过判断数值的机器码的低位来判断类型的。
最初的版本,JS 中数值是以 32位 格式存储,由 类型标记位(1-3位) 和 真实值 组成,类型标记存储在低位,其中几种类型如下:
- 000 表示对象
- 001 表示整型(int)
- 010 表示双精度浮点型(double)
- 100 表示 string
- 110 表示 boolean
3.缺陷:
因为 JavaScript 的变量是没有类型的,所以判断类型都是对变量所持有的值的判断。使用 typeof
对未声明 和 目前没有值的 变量进行判断的处理是非常不好的。这本事两种完全不同的情况,但是浏览器的处理结果却是一样的,如下:
对于没有被声明的 abcnnn
和 声明却没有赋值的 p
,返回结果却都是 undefined
。
typeof abcnnn // ReferenceError:abcnnn is not defined
let p
typeof p // undefined
// 强调!!!‘is not defined’ 和‘undefined’ 是两码事
// 或许 ‘is not defined’ 改成 ‘is not declared’ 会好点
2.instanceof
1.基本使用
instanceof 返回一个布尔值。因为引用类型保存在栈中的是一个地址,所以没有办法通过 typeof
找到数值判断机器码。要使用另外一个 instanceof
来判断。
数据 instanceof 类型; // 返回 true or false
instanceof
是判断一个示例是否属于某一种类型。
2.实现原理:
通过在原型链上查找,跟判断的类型对比,如果查找到一样的,返回 true
,否则返回 false
。
const instanceOf = (leftVaule,rightVaule) => {
const rightProto = rightVaule.prototype;
leftVaule = leftVaule.__proto__;
while(true){
if (leftVaule === null){
return false;
}
if(leftVaule === rightProto){
return true;
}
leftVaule = leftVaule.__proto__;
}
}
补充:
在 ES6 中,instanceof
操作符会使用 Symbol.hasInstance
函数来确定关系。 根据 ECMAScript 规范,这个符号作为一个属性表示 :一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例。
这个属性定义在 Function
的原型上,因此默认在所有函数和类上都可以调用。由于 instanceof
操作符会在原型链上寻找这个属性定义,就跟在原型链上寻找其他属性一样,因此可以在继承的类上通 过静态方法重新定义这个函数:
class Bar {}
class Baz extends Bar {
static [Symbol.hasInstance]() {
return false;
}
}
let b = new Baz();
console.log(Bar[Symbol.hasInstance](b)); // true
console.log(b instanceof Bar); // true
console.log(Baz[Symbol.hasInstance](b)); // false
console.log(b instanceof Baz); // false
3.注意
但是由于 Array
等引用类型本质上也都是对象,所以示例如下:
const a = [];
console.log(a instanceof Object) // true
3.Object.prototype.toString.call()
console.log(Object.prototype.toString.call([])) // [object Array]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call(true)) // [object Boolean]
console.log(Object.prototype.toString.call(100)) // [object Number]
console.log(Object.prototype.toString.call('starry')) // [object String]
console.log(Object.prototype.toString.call(null)) // [object Null]
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(new Set())) // [object Set]
console.log(Object.prototype.toString.call(new Map())) // [object Map]
总结:
typeof
和 instanceof
都有弊端,并不能满足所有场景的需求
typeof
会返回一个变量的基本类型,instanceof
返回的是一个布尔值。instanceof
可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型。typeof
可以判断基础数据类型(null
除外),但是引用数据类型中,除了function
类型以外,其他的也无法判断。- 如果需要通用检测数据类型,可以采用
Object.prototype.toString.call
。
参考资料: 1.JavaScript 高级程序设计 2.The history of “typeof null”
转载自:https://juejin.cn/post/7270317297624531000