一.数据类型
JavaScript的数据类型可分为两大类:基本数据类型和引用数据类型。
1.基本数据类型
基本数据类型有6种:数字(Number)、字符串(String)、布尔值(Boolean)、Undefined、Null、Symbol(ES6新增)。
基础数据类型有以下特点:
- 基本数据类型的值是不可变的,且不可以添加属性和方法。
- 基本数据类型的比较是本身值的比较
- 基本数据类型是存储在栈的
2.引用数据类型
引用数据类型主要有以下几种:对象(Object)、数组(Array)、函数(Function)、还有两个特殊的对象:正则(RegExp)和日期(Date)。
引用数据类型有以下特点:
- 引用数据类型的值是可变的,且可以添加属性和方法
- 引用数据类型的比较是引用对象的比较
- 引用数据类型的值是保存在堆内存的一个对象,栈内存保存的是指向这个对象的指针(或者说堆内存的地址)
二.类型判断
1.typeof
typeof返回一个表示数据类型的字符串,返回结果包括:number、string、boolean、object、undefined、function。typeof可以对基本类型number、string 、boolean、undefined做出准确的判断(null除外,typeof null===“object”,这是由于历史遗留bug);而对于引用类型,除了function之外返回的都是object。但当我们需要知道某个对象的具体类型时,typeof就显得有些力不从心了
typeof 1; // number 有效
typeof ‘ ’;//string 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof new Function(); // function 有效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
2.instanceof
instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型。我们用一段伪代码来模拟instanceof内部执行过程:
instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
//A的内部属性__proto__指向B的原型对象
return true;
}
return false;
}
从上述过程可以看出,当 A 的 proto 指向 B 的 prototype 时,就认为A就是B的实例,我们再来看几个例子:
[] instanceof Array; //true
[] instanceof Object; //true
new Date() instanceof Date;//true
new Date() instanceof Object;//true
function Person(){};
new Person() instanceof Person;//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的实例。
3.toString
前面的typeof和instanceof都有一定局限性,最后一个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(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object Window]