JavaScript类型判断

38次阅读

共计 4179 个字符,预计需要花费 11 分钟才能阅读完成。

JS(ES6)中的基本数据类型:1. 数值型(Number):包括整数、浮点数、2. 布尔型(Boolean)、3. 字符串型(String)、4. 数组(Array)、5. 空值(Null)、6. 未定义(Undefined),基本数据类型是按值访问的,因为可以直接操作保存在变量中的实际值。引用类型:Object、Array、Function、Data,引用数据类型是保存在堆内存中的对象
1.typeof
var a;
console.log(“1:” + typeof a);
var b = null;
console.log(“2:” + typeof b);
var c = undefined;
console.log(“3:” + typeof c);
var d = new Object;
console.log(“4:” + typeof d);
var e = function() {};
console.log(“5:” + typeof e);
var f = {};
console.log(“6:” + typeof f);
var g = ”;
console.log(“7:” + typeof g);
var h = [];
console.log(“8:” + typeof h);
var i = true;
console.log(“9:” + typeof i);
var j = 123;
console.log(“10:” + typeof j);
var k = NaN;
console.log(“11:” + typeof k);
var l = /^[-+]?\d+$/;
console.log(“12:” + typeof l);
打印结果如下
总结:typeof 对 null、undefined、NaN、数组、正则、Object 的类型都为 object

2.constructor
constructor 用于判断一个变量的原型,constructor 属性返回对创建此对象的数组函数的引用. 当一个函数 F 被定义时,JS 引擎会为 F 添加 prototype 原型,然后再在 prototype 上添加一个 constructor 属性,并让其指向 F 的引用, 当执行 var f = new F() 时,F 被当成了构造函数,f 是 F 的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor === F
var F = function(){}
console.log(F.prototype);
var f = new F();
console.log(f.constructor===F) //true
不难看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上,从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型, 也就是说对象的 constructor 属性指向他的构造函数
所以内置对象在内部构建时阔以这样做出判断

注:

null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断
constructor 属性并非一定指向构造函数,他也是可以修改、变更的 (当把 F.prototype = {} 改写后, 会默认把 constructor 覆盖掉)

instanceof
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性
及的构造函数有这些基础类型:String、Number、Boolean、Undefined、Null、Symbol(ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值);
复杂类型:Array,Object;
其他类型:Function、RegExp、Date。
var obj = new Object()
obj instanceof Object // true
注意左侧必须是对象(object),如果不是,直接返回 false,列如:
var num = 1
num instanceof Number // false

num = new Number(1)
num instanceof Number // true
可以看出都是 num,而且都是 1,只是因为第一个不是对象,是基本类型,所以直接返回 false,而第二个是封装成对象,所以 true。这里要严格注意这个问题,有些说法是检测目标的__proto__与构造函数的 prototype 相同即返回 true,这是不严谨的,检测的一定要是对象才行,如:
基础类型
var num = 1
num.__proto__ === Number.prototype // true
num instanceof Number // false

num = new Number(1)
num.__proto__ === Number.prototype // true
num instanceof Number // true
num.__proto__ === (new Number(1)).__proto__ // true
上面例子可以看出,1 与 new Number(1)几乎是一样的,只是区别在于是否封装成对象,所以 instanceof 的结果是不同的,string、boolean 等,这些基础类型一样的。
new String(1) // String {“1”}
String(1) // “1”
new String(1)与 String(1)是不同的,new 是封装成对象,而没有 new 的只是基础类型转换,还是基础类型其他基础类型一样的。
复杂类型,比如数组与对象,甚至函数等,与基础类型不同。
复杂类型
var arr = []
arr instanceof Array // true
arr instanceof Object // true
Array.isArray(arr) // true

复杂类型从字面量是直接生成构造函数的,所以不会像基本类型一样两种情况。但是上面那个问题,当然,基础类型也会有这个问题,就是与 Object 对比。没办法,Object 在原型链的上层,所以都会返回 true,如下:
(new Number(1)) instanceof Object // true
由于从下往上,比如你判断是 Number,那就没必要判断是不是 Object 了,因为已经是 Number 了……
其他类型
var reg = new RegExp(//)
reg instanceof RegExp // true
reg instanceof Object // true

var date = new Date()
date instanceof Date // true
date instanceof Object // true

除了 Function,都一样,具体 Function 如下:

function A() {}
var a = new A()
a instanceof Function // false
a instanceof Object // true
A instanceof Function // true

这里要注意,function A() {}相当于 var A; A = function() {},然后分析:

a 是 new 出来,所以是经过构造,因此已经是对象,不再是函数,所以 false
a 是经过构造的对象,返回 ture 没问题
A 是个函数,这没什么问题

{}.toString.call(obj)
用法如下
console.log({}.toString.call(1));
console.log({}.toString.call(“11”));
console.log({}.toString.call(/123/));
console.log({}.toString.call({}));
console.log({}.toString.call(function() {}));
console.log({}.toString.call([]));
console.log({}.toString.call(true));
console.log({}.toString.call(new Date()));
console.log({}.toString.call(new Error()));
console.log({}.toString.call(null));
console.log({}.toString.call(undefined));
console.log(String(null));
console.log(String(undefined));
返回如下

注意:必须通过 call 或 apply 来调用,而不能直接调用 toString,从原型链的角度讲,所有对象的原型链最终都指向了 Object,按照 JS 变量查找规则,其他对象应该也可以直接访问到 Object 的 toString 方法,而事实上,大部分的对象都实现了自身的 toString 方法,这样就可能会导致 Object 的 toString 被终止查找,因此要用 call/apply 来强制调用 Object 的 toString 方法
jQuery 中的方法 $.type(), 就是用到了 toString
type: function(obj) {
if (obj == null) {
return obj + “”;
}
// Support: Android<4.0, iOS<6 (functionish RegExp)
return typeof obj === “object” || typeof obj === “function” ?
class2type[toString.call(obj) ] || “object” :
typeof obj;
},

分析源代码:
typeof obj === “object” || typeof obj === “function” ? class2type[toString.call(obj) ]

通过判断传入类型,如果是 object 或者 function 类型就直接返回 class2type 中键值是对的结果, 如果不是, 那么一定就是基本类型, 通过 typeof 就可以
class2type[toString.call(obj) ] || “object”

这是为了防止一些未知情况的, 如果未取到, 就返回 object,保证了程序可用性
参考文章:JS 类型判断,typeof/constructor/instanceof 的区别 js 中的 constructor 和 prototypeJS 类型判断 jquery 源码 揭开 js 之 constructor 属性的神秘面纱

正文完
 0