Description
typeof 是否正确判断类型
首先 typeof
能够正确的判断基本数据类型,但是除了null
, typeof null输出的是对象。
但是对象来说,typeof 不能正确的判断其类型, typeof 一个函数可以输出 'function',而除此之外,输出的全是 object,这种情况下,我们无法准确的知道对象的类型。
instanceof是否正确判断类型
instanceof
可以准确的判断复杂数据类型,但是不能正确判断基本数据类型。
instanceof原理
instanceof
是通过原型链判断的,A instanceof B
, 在A
的原型链中层层查找,是否有原型等于B.prototype
,如果一直找到A
的原型链的顶端(null
;即Object.prototype.__proto__
),仍然不等于B.prototype
,那么返回false
,否则返回true
。其原理代码如下:
// L instanceof R
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
var O = R.prototype;// 取 R 的显式原型
L = L.__proto__; // 取 L 的隐式原型
while (true) {
if (L === null) //已经找到顶层
return false;
if (O === L) //当 O 严格等于 L 时,返回 true
return true;
L = L.__proto__; //继续向上一层原型链查找
}
}
使instanceof既能判断基本类型又能判断复杂类型
Symbol.hasInstance
被用于确定构造对象是否是其实例。instanceof
的行为可以通过这个来定制。
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance)
}
}
console.log([] instanceof MyArray); // true
所以我们可以用这个方法来封装instanceof
/**
* isComplex判断是否是复杂数据类型,如果是返回true,否则返回false
* @param {*} data 需要被判断类型的数据
*/
function isComplex(data) {
if (data && (typeof data === 'object' || typeof data === 'function')) {
return true;
}
return false;
}
/**
* 定义自己的基本数据类型
*/
class PrimitiveString {
static [Symbol.hasInstance](data) {
return typeof data === 'string';
}
}
class PrimitiveNumber {
static [Symbol.hasInstance](data) {
return typeof data === 'number';
}
}
class PrimitiveUndefined {
static [Symbol.hasInstance](data) {
return typeof data === 'undefined';
}
}
class PrimitiveBool {
static [Symbol.hasInstance](data) {
return typeof data === 'boolean';
}
}
class PrimitiveNull {
static [Symbol.hasInstance](data) {
return data === null;
}
}
class PrimitiveSymbol {
static [Symbol.hasInstance](data) {
return typeof data === 'symbol';
}
}
/**
* 测试
*/
let num = 2;
console.log(num instanceof PrimitiveNumber); //true
console.log('isComplex: ', isComplex(num));
let str = 'Yvette';
console.log(str instanceof PrimitiveString); //true
console.log('isComplex: ', isComplex(str));
let flag = false;
console.log(flag instanceof PrimitiveBool); //true
console.log('isComplex: ', isComplex(flag));
let und = undefined;
console.log(und instanceof PrimitiveUndefined); //true
console.log('isComplex: ', isComplex(und));
let nul = null;
console.log(nul instanceof PrimitiveNull); //true
console.log('isComplex: ', isComplex(nul));
let sym = Symbol(10);
console.log(sym instanceof PrimitiveSymbol); //true
console.log('isComplex: ', isComplex(sym));
console.log('isComplex: ', isComplex(isComplex)); //true
判断数据类型除了typeof、instanceof还有constructor、Object.prototype.toString共四种
使用constructor
console.log('22'.constructor === String) // true
console.log(true.constructor === Boolean) // true
console.log([].constructor === Array) // true
console.log(document.constructor === HTMLDocument) // true
console.log(window.constructor === Window) // true
console.log(new Number(22).constructor === Number) // true
console.log(new Function().constructor === Function) // true
console.log((new Date()).constructor === Date) // true
console.log(new RegExp().constructor === RegExp) // true
console.log(new Error().constructor === Error) // true
1、null
和 undefined
是无效的对象,因此是不会有 constructor
存在的,这两种类型的数据需要通过其他方式来判断。
2、函数的 constructor
是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype
后,原有的 constructor
引用会丢失,constructor
会默认为 Object
使用Object.prototype.toString
console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]
function Person(){}
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log(Object.prototype.toString.call(haoxl));//[object Object]
在任何值上调用 Object
原生的 toString()
方法,都会返回一个 [object NativeConstructorName]
格式的字符串。对于 Object
对象,直接调用 toString()
就能返回 [object Object]
。而对于其他对象,则需要通过 call / apply
来调用才能返回正确的类型信息。
但是它不能检测非原生构造函数的构造函数名。