JavaScript 数据类型与判断方法
JavaScript 数据类型
在 ECMAScript 规范中,定义了7种数据类型,分为基本数据类型和引用数据类型。
基本数据类型:String、Number、Boolean、Symbol、Undefined、Null;
引用数据类型:Object、Function、Date、Array、RegExp 等等;(都是对象类型)
基本数据类型
基本数据类型也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈中,即按值访问。所以修改其中任何一个都不会对另一个有影响。
var a = 1;
var b = a;
a = 2;
console.log(a,b); // 2,1
引用数据类型
引用数据类型又称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆中,而存储在变量处的值是一个指针,指向存储对象的内存处,即按址访问。所以如果赋值之后改变其中任何一个值,对另一个值都有影响。
var obj = {name: 'zhangsan',age: 25};
var obj1 = obj;
obj.name = 'lisi';
console.log(obj,obj1); // {name: 'lisi',age: 25},{name: 'lisi',age: 25}
数据类型的判断方法
typeof
typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示,包括以下7中:
number、boolean、string、function、undefined、symbol、object。
typeof ''; // string 有效
typeof 1; // number 有效
typeof Symbol(); // symbol 有效
typeof true; // boolean 有效
typeof undefined; // undefined 有效
typeof new Function(); // function 有效
typeof null; // object 无效
typeof [] ; // object 无效
typeof new Date(); // object 无效
typeof new RegExp(); // object 无效
对于基本类型,除了 null 以外,均可以返回正确的结果。
对于引用类型,除了 function 以外,一律返回 object 类型。
其中,null 有属于自己的数据类型 Null,引用类型中的数组、日期、正则也都有属于自己的具体类型,而 typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型。
instanceof
instanceof 是用来判断 A 是否为 B 的实例,表达式为 A instanceof B,如果 A 为 B 的实例,则返回 true,否则返回 false。特别注意的是,instanceof 检测的是原型,我们用一段代码来模拟其内部执行过程:
从上述过程中可以看出,当 A 的__proto__ 指向 B 的 prototype 时,就认为 A 是 B 的实例,我们再来看下面的例子:
[] instanceof Array; // true
{} instanceof Object; // true
{} instanceof Object; // true
function Person(){};
new Person() instanceof Person; // true
[] instanceof Object; // true
new Date() instanceof Object; // true
new Person instanceof Object; // true
虽然 instanceof 可以判断出 [ ] 是 Array 的实例,但是它也认为 [ ] 是 Object 的实例,让我们来看一下 [ ]、Array、Object 三者之间的关系:
从 instanceof 能够判断出 [ ].__ proto __指向了 Array.prototype,而Array.prototype.__proto__又指向了 Object.prototype,最终 Object.prototype.__proto__指向了 null,所以 [ ]、Array、Object就在内部形成了一条原型链:
从原型链可以看出,[ ] 的__proto__直接指向了 Array.prototype,间接指向了 Object.prototype,所以按照 instanceof 的判断规则,[ ] 就是 Object 的实例。依次类推,类似的 new Date()、new Person() 也会形成一条原型链,都会指向 Object.prototype。因此,instanceof 只能用来判断两个对象是否属于实例关系,而不能判断一个对象的实例具体属于哪种类型。
instanceof 操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
var arr =new xArray(1,2,3); // [1,2,3]
arr instanceof Array; // false
针对数组的这个问题,ES5 提供了 Array.isArray() 方法。该方法用于确认某个对象本身是否为 Array 类型,而不区分该对象在哪个环境中创建。
constructor
constructor:当一个函数 F 被定义时,JS 引擎会为 F 添加 prototype 原型,然后再在 prototype 上添加一个 constructor 属性,并让其指向F的引用。如下图:
当执行 var f = new F()
时,F 被当做了构造函数,f 是 F 的实例对象,此时 F 原型上的 constructor 传递到了 f 上,所以 f.constructor == F; // true
。
可以看出,F 利用原型对象上的 constructor 引用了本身,当 F 被当做构造函数来创建对象是,原型上的 constructor 就被遗传到了新创建的对象上,从原型链的角度来讲,构造函数 F 就是新对象的类型。这样做的意义就是,让新的对象在诞生之后,就具有可追溯的数据类型。
同样,JavaScript 中的内置对象在内部构建时也是这样做的:
值得注意的是:
1、null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
2、函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object。
因为 prototype 被重新赋值的是一个 {},{} 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 {},也就是 Object 本身。
因此为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。
toString
toString 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]]。这是一个内部属性,其格式是 [object Xxx],其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object]。而对于其他对象,则需要通过 call/apply 来调用才能返回正确的类型信息。
jquery.type()
jquery.type():如果对象是 undefined 或者 null,则返回相应的 ‘undefined’ 或 ‘null’。
如果对象有一个内部的 [[Class]] 和一个浏览器的内置对象的 [[Class]] 相同,返回相应的 [[Class]] 名字。