typeof
typeof 对于判断简单数据类型简单有效,包装类型的简单数据类型除外
基本数据类型的判断(OK)
// 数值typeof 37 === 'number';typeof 3.14 === 'number';typeof(42) === 'number';typeof Math.LN2 === 'number';typeof Infinity === 'number';typeof NaN === 'number'; // 尽管它是 "Not-A-Number" (非数值) 的缩写typeof Number(1) === 'number'; // Number 会尝试把参数解析成数值typeof 42n === 'bigint';// 字符串typeof '' === 'string';typeof 'bla' === 'string';typeof `template literal` === 'string';typeof '1' === 'string'; // 注意内容为数字的字符串仍是字符串typeof (typeof 1) === 'string'; // typeof 总是返回一个字符串typeof String(1) === 'string'; // String 将任意值转换为字符串,比 toString 更安全// 布尔值typeof true === 'boolean';typeof false === 'boolean';typeof Boolean(1) === 'boolean'; // Boolean() 会基于参数是真值还是虚值进行转换typeof !!(1) === 'boolean'; // 两次调用 ! (逻辑非) 操作符相当于 Boolean()// Symbolstypeof Symbol() === 'symbol';typeof Symbol('foo') === 'symbol';typeof Symbol.iterator === 'symbol';// Undefinedtypeof undefined === 'undefined';typeof declaredButUndefinedVariable === 'undefined';typeof undeclaredVariable === 'undefined';// 对象typeof {a: 1} === 'object';
引用数据类型的判断
但是对引用数据类型的判断作用不大,除 function外,其他都返回 object,业务中我们通常需要知道它具体的类型
typeof {a: 1} === 'object';typeof [1, 2, 4] === 'object';typeof new Date() === 'object';typeof /regex/ === 'object';
typeof function() {} === 'function';typeof class C {} === 'function'typeof Math.sin === 'function';
包装类型的基本数据类型
迷惑吧!
typeof new Boolean(true) === 'object';typeof new Number(1) === 'object';typeof new String('abc') === 'object';
在lodash中 在判断基础数据类型前 会判断是否是包装数据类型
function isObjectLike(value) {return typeof value === 'object' && value !== null}
typeof null
typeof null === 'object';
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 “object”。
instanceof
对比实例原型链上的基类
实例.proto == 基类.prototype
function Car(make, model, year) {this.make = make;this.model = model;this.year = year;}const auto = new Car('Honda', 'Accord', 1998);console.log(auto instanceof Car);// expected output: trueauto.__proto__ == Car.prototypeconsole.log(auto instanceof Object);// expected output: trueauto.__proto__ == Object.prototype
验证原理
验证一下确实是对比的proto 而不是构造方法里的prototype 有人说是这样的
const auto1 = new Car('Honda', 'Accord', 1998);const auto2 = new Car('Honda', 'Accord', 1998);
auto1 instanceof Cartrueauto2 instanceof Cartrue
删掉
auto1.__proto__ = nullnullauto2.constructor = nullnull
结果
auto1 instanceof Carfalseauto2 instanceof Cartrue
结论
instanceof原理
实例.proto == 基类.prototype
prototype给instanceof带来的风险
auto2 instanceof Cartrueauto2.__proto__ == Car.prototypetrue
操作
Car.prototype = null
auto2.__proto__ == Car.prototypefalseauto2 instanceof CarVM1487:1 Uncaught TypeError: Function has non-object prototype 'null' in instanceof checkat Function.[Symbol.hasInstance] (<anonymous>)at <anonymous>:1:7
由于基类的prototype 可改变,所以 instanceof这种对比 是不安全的
Object.prototype.toString()
每个对象都有一个 toString() 方法,默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回一个字符串 “[object type]”,其中 type 是对象的类型。
var o = new Object();o.toString(); // [object Object]
为什么不能直接使用toString()
内置对象或者自定义类型的对象可能会实现自己的 toString 方法或者根本没有定义该方法,导致返回的不再是 “[object type]” 或者直接报错
var str = new String('hello')str.toString() // "hello"123..toString() // "123"null.toString() // Uncaught TypeError: Cannot read property 'toString' of nullundefined.toString() // Uncaught TypeError: Cannot read property 'toString' of undefined
所以需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用(不陌生吧,改变 this 指向)
var toString = Object.prototype.toString;toString.call(new String); // "[object String]"toString.call('hello'); // "[object String]"toString.call(Math); // "[object Math]"toString.call(123); // "[object Number]"toString.call(true); // "[object Boolean]"toString.call(123n); // "[object BigInt]"toString.call(new Date); // "[object Date]"toString.call(Symbol()) // "[object Symbol]"toString.call(() => {}) // "[object Function]"toString.call([1, 2]); // "[object Array]"toString.call(new Map) // "[object Map]"toString.call(function* () {}); // "[object GeneratorFunction]"toString.call(Promise.resolve()); // "[object Promise]"// ES5 中才实现下面的功能toString.call(undefined); // "[object Undefined]"toString.call(null); // "[object Null]"
ECMAScript 内置的针对某个类型的判断方法
Array.isArray()
Array.isArray([1]); // trueArray.isArray(new Array('a', 'b', 'c', 'd')); // true
总结
基本数据类型的判断使用 typeof 足够,instanceof由于判断的是对象的prototype,具有可变性,所以相对不安全。
引用数据类型使用Object.prototype.tosString.call(obj) 最为安全可靠
