【每日一题】 JavaScript数据结构|JavaScript如何判断数据类型?实现一个instanceof

96 阅读2分钟

【每日一题】 JavaScript数据结构|JavaScript如何判断数据类型?实现一个instanceof

JavaScript判断数据类型的方法大致有四种:typeofinstanceof、constructor、Object.prototype.toString.call()

typeof

console.log(typeof 11);               // number
console.log(typeof true);            // boolean
console.log(typeof 'bear');           // string
console.log(typeof []);              // object    
console.log(typeof function(){});    // function
console.log(typeof {});              // object
console.log(typeof undefined);       // undefined
console.log(typeof null);            // object// 其中数组、对象、null都会被判断为object

instanceof

  • Instanceof 用于判断对象的类型,其运行机制是判断在其原型链能否找到该类型的原型
console.log(11 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('bear' instanceof String);                // false // instanceof 无法判断基本数据类型console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true
// instanceof 可以正确判断引用数据类型
如何实现一个instanceof
  • instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
function myInstanceof(leftValue, rightValue) {
  let proto = Object.getPrototypeOf(leftValue), // 获取对象的原型
      prototype = rightValue.prototype; // 获取构造函数的 prototype 对象
​
  // 判断构造函数的 prototype 对象是否在对象的原型链上
  // 循环判断对象的原型是否等于类型的原型,直到对象原型为null
  while (true) {
    if (!proto) return false;
    if (proto === prototype) return true;
​
    proto = Object.getPrototypeOf(proto);
  }
}

constructor

  • constructor本来是原型对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的
console.log((11).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('bear').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // truefunction Fn(){};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor===Fn);    // false
console.log(f.constructor===Array); // true
// 由于constructor属性是可以变更的,也会导致检测出的结果不正确console.log(f.constructor===Fn);    // false
console.log(f.constructor===Array); // true
console.log((null).constructor) //报错
console.log((undefined).constructor) //报错
// undefined和null没有constructor属性,所以判断时代码可能会报错--这很致命,会导致代码运行不下去,所以只有在确定待判断的值不是undefined和null才能使用

Object.prototype.toString.call()

Object.prototype.toString.call() 使用Object对象的原型方法toString来判断数据类型,是一种较为通用可靠的判断方式

var a = Object.prototype.toString;
 
console.log(a.call(11));  // [object Number]
console.log(a.call(true));  // [object Boolean]
console.log(a.call('bear'));  // [object String]
console.log(a.call([]));  // [object Array]
console.log(a.call(function(){}));  // [object Function]
console.log(a.call({}));  // [object Object]
console.log(a.call(undefined)); // [object Undefined]
console.log(a.call(null));  // [object Null]// 获取this指向的那个对象的[[Class]]属性的值。
// 计算出三个字符串"[object "、 第一步的操作结果Result(1)、 以及 "]" 连接后的新字符串。
// 返回第二步的操作结果Result(2),也就是类似 [object className] 这种格式字符串。
// [[class]]类属性:对象的类属性(class attribute)是一个字符串,用以表示对象的类型信息。并只有一种间接的方法可以查询到它。默认的toString方法(继承自Object.prototype)返回了如下格式的字符串:[object class] 

\