js检测数据类型的四种方法

一.typeof 

返回的结果都是字符串

缺点:不能细分对象

基本数据类型 :除null以外均可返回正确结果

引用数据类型:除function以外一律返回object类型

null返回object类型

function返回function类型

检测未被声明的变量 undefined

那么为什么检测null却返回了object类型呢??

原理

js在底层存储变量的时候会按照计算机存储的二进制进行检测

000 对象

010浮点数

100 字符串

110布尔

1 整数

null 00000,,, 

-2^30 undefined

type of在判断null的时候由于null所有的机器码均为0,因此被当做了对象来看待

	let n = 100;
		console.log(typeof n);//"number"
		console.log(typeof typeof n);//typeof "number"--->"string"

		console.log(typeof null);//object

		let fn = function fn() {

		}
		console.log(typeof fn);//function

		a = "hello"
		console.log(typeof a);//string

		console.log(typeof [10, 20]);//"object"

 应用:

  •   + 检测除null之外的原始值类型可以使用他
  •    + 检测是否为对象  if(obj!==null && /^(object|function)$/.test(typeof obj)){...}
  •   + 检测某个东西是否兼容  if(typeof Symbol!=="undefined"){...}

二. instanceof

临时用来检测数据类型 本意:检测当前的实例是否属于这个类

instanceof  能细分对象(通过原型链,万物皆对象)

缺点:

  • 对原始值类型无效:instanceof左侧只要是原始值类型,结果就是false,默认不会进行“装箱”
  • 无法检测是否为“标准普通对象”:因为所有对象都是Object的一个实例,检测结果都是true
  • 因为我们可以修改原型链的指向,所以检测的结果不一定是准确的

原理

 传统版本

按照原型链进行检测(只要当前检测的构造函数[它的原型对象] 出现在实例的原型链上,则检测的结果是true),沿着原理链一直查找直到object.prototype都没有就是false

let arr = [10, 20];
		console.log(arr instanceof Array);//true
		console.log(arr instanceof Object);//true
		console.log(arr instanceof Date);//false

		let n = 10;//基础类型
		console.log(n instanceof Number);//false

  新版本

在Function.prototype上有一个Symbol.hasInstance属性方法(所有函数都可以使用),当我们基于 “[对象] instanceof [构造函数]”检测处理的时候,内部是这样处理的:

 [构造函数][Symbol.hasInstance]([对象])

class Fn {
name = 'Fn';
x = 10;
y = 20;
sum() {
  if (!this.name) throw new TypeError('this.name is not defined');
  // ...
}
// 只要基于ES6中的class创建类,基于“static xxx”这种语法重写Symbol.hasInstance才有用;如果是ES5创建的类,基于 Fn[Symbol.hasInstance]=xxx 这样重写是无效的!!
static[Symbol.hasInstance](obj) {
  return (obj.name && Object.getPrototypeOf(obj) === Fn.prototype) ? true : false;
}
}
let f1 = new Fn;
let f2 = new Fn;
console.log(f1 instanceof Fn); //true
f1.sum();

let obj = {};
Object.setPrototypeOf(obj, Fn.prototype);
console.log(obj instanceof Fn); //Fn[Symbol.hasInstance](obj) false
console.log(obj instanceof Fn); //true
obj.sum(); //报错 

原型链的指向可以随意改动 导致检测不准确

	function Fn() {

		}
		Fn.prototype = Array.prototype;
		let f = new Fn();
		console.log(f instanceof Array);//true

三 constructor  

constructor  指回构造函数

作用:

  • + 可以检测是否为纯粹对象(标准普通对象)
  • + 对原始值(除null/undefined,因为他们两个无法进行成员访问)也有效
  • +(查看值是哪个构造函数)能细分对象--->比instanceof更精准
let arr = [10, 20];
		console.log(arr.constructor === Array);//true
		console.log(arr.constructor === Object);//false

缺点 原型重定向也会影响 constructor  的判断

下面案例中把fn 的原型重定向了 新的原型对象中没有了 constructor 它会根据原型链找到object

	function Fn(){

		}
		Fn.prototype={};
		let f=new Fn();

		console.log(f.constructor===Fn);//false
		console.log(f.constructor===Object);//true

四 Object.prototype.toString.call()

Object.prototype.toString.call  是js中唯一一个检测数据类型最完美的

大部分内置类的原型上都有tostring方法一般都是转为字符串的,但是object.prototype.tostring是检测数据类型的 返回值中包含了自己的构造函数信息 返回的结果 “[object ?]”

 ?是啥值

  •   + [value][Symbol.toStringTag] 有这个属性,属性值是啥,则结果中的“?”就是啥
  •   +Math & GeneratorFunction.prototype & Generator.prototype & Promise.prototype ...
  •   + 没有这个属性则一般找到的是自己所属的构造函数(以内置的为主)
	let arr = [10, 20, 30];
		console.log(Object.prototype.toString.call(arr));//[object Array]
		console.log(Object.prototype.toString.call(10));//[object Number]

 扩展

 重写内置instanceof

// 重写内置instanceof
var instance_of = function instance_of(obj, Ctor) {
  // 右侧必须是一个函数
  if (typeof Ctor !== "function") throw new TypeError("Right-hand side of 'instanceof' is not callable");
  // 原始值检测都是false
  if (obj == null || !/^(object|function)$/.test(typeof obj)) return false;
  // 构造函数必须具备prototype
  if (!Ctor.prototype) throw new TypeError("Function has non-object prototype 'undefined' in instanceof check");
  // 支持Symbol.hasInstance的使用这个方法处理
  if (typeof Symbol !== "undefined") return Ctor[Symbol.hasInstance](obj);
  // 不支持:自己按照原型链查找
  let proto = Object.getPrototypeOf(obj);
  while (proto) {
    if (proto === Ctor.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
  return false;
};
let arr = [10, 20];
console.log(instance_of(arr, Array)); //true
console.log(instance_of(arr, RegExp)); //false
console.log(instance_of(arr, Object)); //true 

总结

1. typeof 二进制 不能细分对象

    2. instanceof 临时 能细分对象(通过原型链,万物皆对象)

    缺点:不能检测基础类型(false),检测不准确(原型链可以修改)

    直接(es6)修改[Symbol.hasInstance]---》检测不准确

    3. constructor 临时 (查看值是哪个构造函数)能细分对象--->比instanceof更精准

    缺点:检测不准确,可以修改

    4.最完美的 Object.prototype.toString.call()

------------------------------------------------完结-----------------------------------------------------------------

-----------------------------------------------接受大佬们的批改和指点,欢迎留言--------------------------------

你可能感兴趣的:(JS基础,javascript,前端)