JS之数据类型转化

数据类型

JavaScript的数据类型有七种:

Boolean:布尔值,true 和 false 两个特定值

Null:表示无值,即此处的值就是“无”的状态

Undefined: 表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值

Number:整数和小数

String:字符组成的文本

Symbol (这个是ES6新定义的数据类型)

Object:各种值组成的集合

其中Boolean、Null、Undefined、Number、String和Symbol称为原始类型,即它们是最基本的数据类型,不能再细分。而 Object 称为合成类型,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。其中对象又可分成三个子类型:
侠义的对象(object)、数组(array)、函数(function)

数据类型检测

在JavaScript中有四种方法,可以确定一个值到底是什么类型:

typeof运算符

instanceof运算符

constructor运算符

Object.prototype.toString方法

typeof运算符

instanceof运算符

instanceof 运算符用于检查某个对象的原型链是否包含某个构造函数的 prototype 属性。

使用instanceof来判断A是否为B的实例对,表达式为A instanceof B,如果A是B的实例则返回true,否则返回false。

1
2
3
4
5
6
7
8
// 比如直接原型关系
function A () {}
(new A) instanceof A; // => true
// 原型链上的间接原型
function B () {}
B.prototype = new A
(new B) instanceof A // => true

在JavaScript原型继承结构里面,用[[Prototype]]表示对象隐式的原型,在JavaScript中用proto表示,并且在Firefox和Chrome浏览器中是可以访问得到这个属性的,但是IE下不行。所有JavaScript对象都有proto属性,但只有Object.prototype.proto为null,前提是没有在Firefox或者Chrome下修改过这个属性。这个属性指向它的原型对象。至于显示的原型,在JavaScript里用 prototype 属性表示。

instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。

constructor运算符

当一个函数foo被定义时,JavaScript会给foo函数添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向foo的引用,如下:

当执行var bar = new foo()时,foo被当成了构造函数,bar是foo的实例对象,此时foo原型上的constructor传递到了bar上,因此bar.constructor == foo(返回的是一个true)。

可以看出,JavaScript在函数foo的原型上定义了constructor,当foo被当作构造函数用来创建对象时,创建的新对象就被标记为foo类型,使得新对象有名有姓,可以追溯。同理,JavaScript中的数据类型也遵守这个规则:

1
2
3
4
5
6
7
8
9
10
11
12
'123'.constructor == String;
123.constructor == Number;
true.constructor == Boolean;
[1, 2, 3].constructor == Array;
{}.constructor == Object;
new Function().constructor == Function;
new Date().constructor == Date;
new Error().constructor == Error;
document.constructor == HTMLDocument;
window.constructor == Window;
null.constructor == Object;
undefined.constructor == Object;

在JavaScript中null和undefined是比较特殊的数据类型,也是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。另外,JavaScript对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object。

为什么变成了Object?

prototype被重新赋值的是一个{},{}是new Object()的字面量,因此new Object()会将Object原型上的constructor传递给{},也就是Object本身。因此,为了规范,在重写对象原型时一般都需要重新给constructor赋值,以保证实例对象的类型不被改写

Object.prototype.toString

toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,… 基本上所有对象的类型都可以通过这个方法获取到。

1
2
3
4
5
6
7
8
9
10
11
12
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 global] window是全局对象global的引用

需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString()。

强制转化

强制转换主要是指使用Number()、String()和Boolean()三个构造函数,手动将各种类型的值,转换成number、string和boolean。

使用Number()函数,可以将任意类型的值转化成数值

使用String()函数,可以将任意类型的值转换成字符串

使用Boolean()函数,可以将任意类型的变量转换为布尔值


Boolean()的转换规则相对简单:除了以下六个值的转换结果为false,其他的值全部为true。

1
2
3
4
5
Boolean(undefined); // => false
Boolean(null); // => false
Boolean(0); // => false
Boolean(NaN); // => false
Boolean(''); // => false

注意:所有对象,包括空对象的转换结果都是true,甚至连false对应的布尔对象new Boolean(false)也是true:

1
2
3
Boolean({}); // => true
Boolean([]); // => true
Boolean(new Boolean(false)); // => true