已同步到个人博客,欢迎访问。
最常用的判断方法是Object.prototype.slice.call()
,其他判断的方法都有着各种问题:
Array.isArray
判断数组,需要ES6的支持typeof
有各种特殊情况instanceof
对于字面量不适用,并且在iframe场景中有问题constructor
是可以手动改写的Object.prototype.toString
也有着风险:Object.prototype.toString
的结果可以使用Symbol.toStringTag
定义(2019.02.01)
typeof
不太靠谱的方法,对于基本类型是可以的
typeof 123
// "number"
typeof '123'
// "string"
typeof true
// "boolean"
typeof undefined
// "undefined"
对于引用类型行不通,判断结果都是object
typeof []
// "object"
typeof new Array()
// "object"
typeof {}
// "object"
typeof null
// "object"
typeof JSON
// "object"
typeof Math
// "object"
instanceof
instanceof
运算符用来验证原型对象与实例对象之间的关系。
当a.___proto___ === A.prototype
成立时,instanceof
返回true
var a = [],
b = '21',
c = {};
a instanceof Array; // true
b instanceof Array; // false
c instanceof Array; // false
但是注意:
1 instanceof
只对引用类型有效,对于基本类型字面量是无效的,因为基本类型不是对象,不存在原型链的继承关系
[] instanceof Array;
// true
123 instanceof Number;
// false
Number(123) instanceof Number
// false
new Number(123) instanceof Number
// true
2 instanceof
存在继承关系,对于引用类型都是Object
的实例
[] instanceof Array;
// true
[] instanceof Object;
// true
3 instanceof
在iframe的场景中有可能出现误判
const a = [1, 2, 3];
const iframe = document.querySelector('#iframe');
console.log(a instanceof Array); // ture
console.log(a instanceof iframe.contentWindow.Array); // false
console.log(iframe.contentWindow.Array === Array); // false
可以认为宿主和iframe是两套JS的执行环境,环境中的Array是不同的,所以判断会出现问题。
constructor
实质上实例是没有constructor
属性的,其constructor
属性是继承自原型的:
function Person(){};
let p = new Person();
p.constructor === p.__proto__.constructor;
// ture
p.constructor === Person.prototype.constructor
// true
应用时:
var a = [],
b = '21',
c = {};
console.log(a.constructor === Array); // true
console.log(b.constructor === Array); // false
console.log(c.constructor === Array); // false
它的主要问题是:constructor
是可以手动更改的,当通过原型继承时,constructor
会被改写
function Person() {};
function Man() {};
Man.prototype.constructor === Man;
// true
Man.prototype = new Person();
Man.prototype.constructor === Person;
// true
instacnceof
和constructor
的区别instanceof
是操作符,而constructor
是继承构造函数的原型的一个属性instanceof
对于基本类型的字面量是无效的(返回false
),基本类型的字面量的constructro
不存在instancoeof
存在继承性,引用类型都是Object
的实例,而constructor
是可以认为改写的undefined instanceof Object;
null instanceof Object;
null.constructor
undefined.constructo
Array.isArray()
ES6的Array.isArray()
方法可以来判断数组的类型
var a = [],
b = '21',
c = {};
console.log(Array.isArray(a)); // true
console.log(Array.isArray(b)); // false
console.log(Array.isArray(c)); // false
toString
方法首先要知道,调用Object.prototype.toString
返回结果都是[object xxx]
的格式,例如:
Object.prototype.toString.call({})
"[object Object]"
Object.prototype.toString.call('')
"[object String]"
Object.prototype.toString.call([])
"[object Array]"
Object.prototype.toString.call(function (){})
"[object Function]"
Object.prototype.toString.call(new Date())
"[object Date]"
Object.prototype.toString.call(true)
"[object Boolean]"
构造一个函数,isType
,传入要验证的类型,返回值是一个新的函数:
function isType(type) {
return function(obj) {
return Object.prototype.toString.call(obj) === `[object ${type}]`
}
}
const isArray = isType('Array')
const isString = isType('String')
console.log(isArray[1, 2, [3]]); // true
console.log(isString({})); // false
这是一个比较稳妥的判断方法。
Object.prototype.toString
也有着风险:Object.prototype.toString
的结果可以使用Symbol.toStringTag
定义:
var o = { [Symbol.toStringTag]: "MyObject" };
console.log(Object.prototype.toString.call(o)); // [object MyObject]