JS数据类型与判断方法
一、数据类型
五种简单数据类型(值类型)包括:String、Number、Boolean、undefined、Null
一种复杂数据类型(引用类型):Obeject(包括 function、Array、Date)
ES6 中新增了一种 Symbol 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记
Symbol('key')===Symbol('key') // false
Symbol('key')!==Symbol('key') // true
1.undefined:在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined
2.null:null值表示一个空对象指针,而这也正是使用typeof操作符检测null时会返回object的原因
在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息: 000:对象 1:整数 010:浮点数 100:字符串 110:布尔 有 2 个值比较特殊: undefined:用 - (−2^30)表示。 null:对应机器码的 NULL 指针,一般是全零。 javascript 中的 null:既是对象,又不是对象,史称「薛定谔的对象」。 typeof null === 'object'; null instanceof Object === false 而 null instanceof null 会抛出异常: Uncaught TypeError: Right-hand side of 'instanceof' is not an object
3.Number:这种类型用来表示整数和浮点数值,还有一种特殊的数值,即NaN(非数值 Not a Number)。这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以0都会导致错误,从而停止代码执行。但在JavaScript中,任何数值除以0会返回NaN,因此不会影响其他代码的执行。
NaN本身有两个非同寻常的特点。首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。其次,NaN与任何值都不相等,包括NaN本身
二、类型判断
1.typeof
typeof ''; // string 有效 typeof 1; // number 有效
typeof NaN; // number
typeof Symbol(); // symbol 有效 typeof true; //boolean 有效 typeof undefined; //undefined 有效 typeof null; //object 无效 typeof [] ; //object 无效 typeof newFunction(); // function 有效 typeof newDate(); //object 无效 typeof newRegExp(); //object 无效 对于基本类型,除 null 以外,均可以返回正确的结果。 对于引用类型,除 function 以外,一律返回 object 类型。 对于 null ,返回 object 类型。 对于 function 返回 function 类型。 null 有属于自己的数据类型 Null , 引用类型中的 数组、日期、正则 也都有属于自己的具体类型
而 typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型
2.instanceof
instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型
[] instanceof Array; // true [] instanceof Object; // true
instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型
3.constructor
当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F


可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。
同样,JavaScript 中的内置对象在内部构建时也是这样做的

细节问题:
1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

为什么变成了 Object?
因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。
因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。
4.toString
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(newFunction()) ; // [object Function]
Object.prototype.toString.call(newDate()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(newRegExp()) ; // [object RegExp]
Object.prototype.toString.call(newError()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
拓展:
一个判断JS数据类型的函数 function judgeType(change) { if (arguments.length == 0) { return '0';//无参数传入 } if (change === null) { return 'null' } if (change === undefined && arguments.length > 0) { return 'undefined' } if (change instanceof Function) { return 'function' } if (change instanceof Array) { return 'arry' } if (change instanceof Number || typeof change == 'number') { return 'number' } if (change instanceof String || typeof change == 'string') { return 'string' } if (change instanceof Boolean || typeof change == 'boolean') { return 'boolean' } }
三、数据比较
先按如下规则隐式转换,再进行比较。如对象和布尔比较的话,对象 => 字符串 => 数值;布尔值 => 数值。

特殊情况 [] == false; ![] == false; null==null; undefined == null //true undefined和null 比较返回true,二者和其他值比较返回false
四、判断类型是否为数组
1.通过instanceof判断
let a = []; a instanceof Array; //true let b = {}; b instanceof Array; //false 需要注意的是,prototype属性是可以修改的,所以并不是最初判断为true就一定永远为真。 其次,当我们的脚本拥有多个全局环境,例如html中拥有多个iframe对象,instanceof的验证结果可能不会符合预期,例如: //为body创建并添加一个iframe对象 var iframe = document.createElement('iframe'); document.body.appendChild(iframe); //取得iframe对象的构造数组方法 xArray = window.frames[0].Array; //通过构造函数获取一个实例 var arr = new xArray(1,2,3); arr instanceof Array;//false
2.通过constructor判断
let a = [1,3,4]; a.constructor === Array;//true 同样,这种判断也会存在多个全局环境的问题,导致的问题与instanceof相同。
3.通过Object.prototype.toString.call()判断
// 检验是否是数组 let a = [1,2,3] Object.prototype.toString.call(a) === '[object Array]';//true //检验是否是函数 let b = function () {}; Object.prototype.toString.call(b) === '[object Function]';//true //检验是否是数字 let c = 1; Object.prototype.toString.call(c) === '[object Number]';//true
4.通过Array.isArray()判断
let a = [1,2,3] Array.isArray(a);//true
// Array.isArray() 是在ES5中提出,也就是说在ES5之前可能会存在不支持此方法的情况。
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }
五、Object.is
ES6提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
不同之处只有两个:一是 +0 不等于 -0 ,二是 NaN 等于自身。
+0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
ES5 可以通过下面的代码,部署Object.is
Object.defineProperty(Object, 'is', { value: function(x, y) { if (x === y) { // 针对+0 不等于 -0的情况 return x !== 0 || 1 / x === 1 / y; } // 针对NaN的情况 return x !== x && y !== y; }, configurable: true, enumerable: false, writable: true });
参考来源:https://www.cnblogs.com/onepixel/p/5126046.html
https://www.cnblogs.com/chenmeijiao/p/12060845.html

浙公网安备 33010602011771号