JS53 判断JavaScript中变量类型的方法

已同步到个人博客,欢迎访问。

总结

最常用的判断方法是Object.prototype.slice.call(),其他判断的方法都有着各种问题:

  1. Array.isArray判断数组,需要ES6的支持
  2. typeof有各种特殊情况
  3. instanceof对于字面量不适用,并且在iframe场景中有问题
  4. constructor是可以手动改写的

Object.prototype.toString也有着风险:Object.prototype.toString的结果可以使用Symbol.toStringTag定义(2019.02.01)

方法1 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"

方法2: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是不同的,所以判断会出现问题。

方法3: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

instacnceofconstructor的区别

  1. instanceof是操作符,而constructor是继承构造函数的原型的一个属性
  2. instanceof对于基本类型的字面量是无效的(返回false),基本类型的字面量的constructro不存在
  3. instancoeof存在继承性,引用类型都是Object的实例,而constructor是可以认为改写的
undefined instanceof Object;

null instanceof Object;

null.constructor

undefined.constructo

方法4 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

方法5 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]

参考

  • JavaScript高级程序设计(第3版)
  • 掘金 - 高阶函数,你怎么那么漂亮呢!

你可能感兴趣的:(JavaScript)