JavaScript数据类型判断 发表于 2021-09-04 | 更新于 2021-09-04
总字数: 1.4k | 阅读时长: 6分钟 | 阅读量:
JavaScript 数据类型判断 1. typeof 使用 typeof 判断数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 console .log(typeof 1 ); console .log(typeof NaN ); console .log(typeof "1" ); console .log(typeof true ); let s = Symbol ();console .log(typeof s); console .log(typeof undefined ); function islu ( ) { console .log("this is a function!" ); } console .log(typeof islu); let obj = { name : "闲花手札" , }; console .log(typeof obj); console .log(typeof null ); let array = [0 , 1 , 2 , 3 ]; console .log(typeof array);
使用 typeof 可以检测大部分的基本类型。但无法检测出来 null,会认为是对象。 NaN 也会认为是 number。 可以检测出函数,但是对象数组和对象无法区分。 2. instanceof instanceof 可以用来判断对象是否是某个类的实例。instanceof 的实现原理出门左转查看手撕 instanceof
简单说就是左边对象的原型(通过.__proto__
访问)是否和右边对象的原型相等(通过.prototype
访问),如果相等则返回 true。
1 2 3 4 5 6 7 8 9 10 var arr = [1 , 2 , 3 ];var date = new Date ();var fn = function ( ) { alert(123 ); }; console .log(arr instanceof Array );console .log(date instanceof Date );console .log(fn instanceof Function );console .log(Function instanceof Object );console .log(Object instanceof Function );
再来看另外一种情况:
在 a.html 中定义了数组 a:
1 2 3 4 // a.html <script > var a = [1 , 2 , 3 ]; </script >
然后通过 iframe 引入 main.html 页面:
1 2 3 4 5 6 7 8 9 10 // main.html <iframe src ="a.html" > </iframe > <script > var frame = window .frames[0 ]; var a = frame.a; console .log(a instanceof Array ); console .log(a.constructor === Array ); console .log(a instanceof frame.Array); </script >
在 main.html 页面通过 iframe 获取到 a 页面的数组检测,发现 a 不是 Array 的实例对象,这是什么原因呢?
其实 iframe 之间不会共享原型链, 因为他们有独立的执行环境, 所以 frame a 中的数组 a 不会是本执行环境的实例对象.
3. constructor 使用构造函数判断类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 var bool = true ;var num = 123 ;var str = "Davie" ;var arr = [1 , 2 , 3 ];var obj = { name : "Davie" };var fun = function ( ) {};var sy = Symbol ("Davie" );function Person ( ) {}function Student ( ) { Person.call(this ); } var stu = new Student();console .log(bool.constructor === Boolean ); console .log(num.constructor === Number ); console .log(str.constructor === String ); console .log(arr.constructor === Array ); console .log(obj.constructor === Object ); console .log(fun.constructor === Function ); console .log(sy.constructor === Symbol ); console .log(stu.constructor === Student); console .log(stu.constructor === Person);
undefined 和 null 没有 contructor 属性,所以 constructor 不能判断 undefined 和 null 使用 constructor 判断类型是不安全的,因为 contructor 的指向是可以改变的 1 2 arr.constructor = Object ; console .log(arr.constructor === Object );
4. 特性嗅探 或者一些特有的方法,比如数组特有的 sort,slice 等:
1 console .log(typeof arr.sort === "function" );
但是这种方式也不是特别牢靠,因为很难保证其他对象里面没有这些方法。
5. 万能方法 在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。需要注意的是,它不能检测非原生构造函数的构造函数名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 function foo ( ) {}var div = document .createElement("div" );Object .prototype.toString.call(1 );("[object Number]" ); Object .prototype.toString.call(NaN );("[object Number]" ); Object .prototype.toString.call("1" );("[object String]" ); Object .prototype.toString.call(true );("[object Boolean]" ); Object .prototype.toString.call(undefined );("[object Undefined]" ); Object .prototype.toString.call(null );("[object Null]" ); Object .prototype.toString.call(Symbol ());("[object Symbol]" ); Object .prototype.toString.call(foo);("[object Function]" ); Object .prototype.toString.call([1 , 2 , 3 ]);("[object Array]" ); Object .prototype.toString.call({});("[object Object]" ); Object .prototype.toString.call(/\d+/ );("[object RegExp]" ); Object .prototype.toString.call(div);("[object HTMLDivElement]" ); Object .prototype.toString.call( (function ( ) { return arguments ; })() ); ("[object Arguments]" ); Object .prototype.toString.call(new Error ()); Object .prototype.toString.call(new Date ());
从上面的例子可以看到,Object.prototype.toString 方法能有效弥补 typeof 不能很好区分数组 、对象 和函数 的短板。
每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。
Object.prototype.toString 的原理是当调用的时候, 就取值内部的 [[Class]] 属性值, 然后拼接成 ‘[object ‘ + [[Class]] + ‘]’ 这样的字符串并返回. 然后我们使用 call 方法来获取任何值的数据类型。
6. 检测函数 Array.isArray()
用于确定传递的值是否是一个 Array。如果对象是 Array,则返回 true,否则为 false。
1 Array .isArray([1 , 2 , 3 ]);
判断是否是 DOM 元素
在实际项目里面, 有时或许我们需要判断是否是 DOM 元素对象, 那么在判断的时候利用的是 DOM 对象特有的 nodeType 属性:
1 isElement: function (obj ) { return !!(obj && obj.nodeType === 1 );}
判断是否是对象
1 isObject: function (obj ) { var type = typeof obj; return type === 'function' || typeof === 'object' && obj !== null ;}
这里的对象是狭义的, 是通常所指的 key-value 型的集合, 或者是 function 函数并且不为 null.
判断是否是 arguments 对象
判断一个对象是不是 arguments 对象可以通过 Object.prototype.toString 来判断, 但是低版本的浏览器不支持, 他们返回的是 [object Object], 所以需要兼容:
1 isArguments: function (obj ) { return Object .prototype.toString.call(obj) === '[object Arguments]' || (obj != null && Object .hasOwnProperty.call(obj, 'callee' ));}
兼容做法原理是通过对象的 hasOwnProperty 方法来判断对象是否拥有 callee 属性从而判断是不是 arguments 对象.
isNaN()和 Number.isNaN
isNaN 函数可以检测某个值是否是 NaN:
但是:
只要传入的参数不是数字,都会返回 true,但是数组会返回 false,所以任然无法很好进行区分。
ES6 为了修正这个 BUG,引入了 Number.isNaN()
1 2 3 4 5 6 7 8 9 10 11 Number .isNaN(NaN ); Number .isNaN("A String" ); Number .isNaN(undefined ); Number .isNaN({}); Number .isNaN(1 ); Number .isNaN([]);
没有 ES6 的情况下,可以采用以下 polyfill
1 2 3 4 5 if (!Number .isNaN) { Number .isNaN = function (n ) { return typeof n === "number" && window .isNaN(n); }; }