JavaScript数据类型判断
let obj = { name: 'Davie' }; function foo() { console.log('this is a function'); } let arr = [1,2,3]; let s = Symbol(); console.log(typeof 1); // number console.log(typeof '1'); //string console.log(typeof NaN); // number console.log(typeof true); //boolean console.log(typeof s); //Symbol console.log(typeof undefined); //undefined console.log(typeof null); //object console.log(typeof foo); //function console.log(typeof obj); //object console.log(typeof arr); //object
使用typeof可以检测大部分的基本类型。但无法检测出来null,会认为是对象。NaN也会认为是number。可以检测出函数,但是对象数组和对象无法区分。
var name = Symbol(); var obj = { [name]: "Alice" }; 或者 var name = Symbol(); var obj = {}; obj[name] = "Alice"; 或者 var obj = {}; Object.defineProperty(obj,name,{value: 'Alice'});
instanceof可以用来判断对象是否是某个类的实例。简单说就是左边对象(实例对象)的原型(通过.__proto__
访问)是否和右边对象(一般是构造函数)的原型相等(通过.prototype
访问),如果相等则返回true。
var arr = [1, 2, 3]; var date = new Date(); var fn= function () { alert(123); }; console.log(arr instanceof Array);//true console.log(arr instanceof Object);//true 数组也是对象 console.log(date instanceof Date);//true console.log(fn instanceof Function);//true console.log(Function instanceof Object)//true console.log(Object instanceof Function)//true console.log(123 instanceof Number);//false不能判断字面量的基本数据类型 console.log('str' instanceof String)//false
在 a.html中定义了数组a:
// a.html
然后通过iframe引入main.html页面:
// main.html
其实 iframe 之间不会共享原型链, 因为他们有独立的执行环境, 所以 frame a 中的数组 a 不会是本执行环境的实例对象。
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);// true console.log(num.constructor === Number);// true console.log(str.constructor === String);// true console.log(arr.constructor === Array);// true console.log(obj.constructor === Object);// true console.log(fun.constructor === Function);// true console.log(sy.constructor === Symbol);// true console.log(stu.constructor === Student);// true console.log(stu.constructor === Person);// false
arr.constructor = Object console.log(arr.constructor === Object);// true
4. 特性嗅探
或者一些特有的方法,比如数组特有的sort,slice等:
console.log(typeof arr.sort === 'function')
但是这种方式也不是特别牢靠,因为很难保证其他对象里面没有这些方法。
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 Error]" Object.prototype.toString.call(new Date()); // => "[object Date]"
从上面的例子可以看到,Object.prototype.toString 方法能有效弥补typeof不能很好区分数组、对象和函数的短板。
每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。
Object.prototype.toString 的原理是当调用的时候, 就取值内部的 [[Class]] 属性值, 然后拼接成 '[object ' + [[Class]] + ']' 这样的字符串并返回. 然后我们使用 call 方法来获取任何值的数据类型。
Array.isArray()
用于确定传递的值是否是一个Array。如果对象是Array,则返回true,否则为false。
Array.isArray([1, 2, 3]);
判断是否是 DOM 元素
在实际项目里面, 有时或许我们需要判断是否是 DOM 元素对象, 那么在判断的时候利用的是 DOM 对象特有的 nodeType 属性:
isElement: function(obj){ return !!(obj && obj.nodeType === 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], 所以需要兼容:
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:
isNaN(NaN); // true
但是:
isNaN(undefined); // true isNaN({}); // true isNaN([]); // false
只要传入的参数不是数字,都会返回true,但是数组会返回false,所以任然无法很好进行区分。
ES6为了修正这个BUG,引入了Number.isNaN()
Number.isNaN(NaN); // true Number.isNaN('A String'); // false Number.isNaN(undefined); // false Number.isNaN({}); // false Number.isNaN(1); // false Number.isNaN([]); // false
没有ES6的情况下,可以采用以下polyfill
if (!Number.isNaN) { Number.isNaN = function(n) { return ( typeof n === "number" && window.isNaN( n ) ); }; }