转载

JavaScript 中的数据类型

学一门编程语言,无非两方面:一是语法,二是数据类型。类C语言的语法不外乎if、while、for、函数、算术运算等,面向对象的语言再加上object。语法只是语言设计者预先做的一套规则,不同语言语法不尽相同,但都有一些共通点,对于熟悉一两门编程语言的人,学其他的编程语言时,语法往往不是问题(当然,如果你一直学的是类C语言,那么首次接触lisp时肯定也要花些时间),学习的重点往往是数据类型及其相关操作上,不是有句老话:“数据结构+算法=程序”!其次,有些语言的语法本身就存在设计问题(javascript更甚),我们没必要深究这些点,当然,如果你自诩geek,可以把玩把玩。

本文将对javascript中的数据类型做一个详尽的介绍。

弱类型 vs 强类型

鉴于javascript的设计理念,javascript被设计成一种弱类型的语言。

说到这里,难免要说一下,弱类型与强类型的区别。

一些人会误以为这两者的差别就是“强类型的语言在声明一个变量时需要指明它的类型,而弱类型的则不用”。其实这种观点是错误的。比如下面这个Java代码片段:

String s = "hello" ;
int l = s.getBytes().length;

编译器是怎么知道 .length 是合法的表达式呢?这是因为编译器知道 s 的数据类型为 String ,当调用 StringgetBytes 方法时,返回值的数据类型为 byte[] ,所以 .length 是合法的表达式。

这两者真正的区别是:

在强类型的语言,每个表达式的类型都能够在编译时确定,并且只允许适用于该类型的操作;弱类型的语言允许对任意类型施加任何操作,只是这个操作有可能在运行时报错。

数据类型

javascript中的数据类型很简单,大致可以分为两类:一是基本数据类型,包含 Undefined , Null , Boolean , Number , String ;除此之外的所有变量都是对象类型。

  • Undefined 类型只有一个值,为 undefined
  • Null 类型只有一个值,为 null
  • Boolean 类型有两个值,为 truefalse
  • Number 类型的值是遵循IEEE 754标准的64位浮点数的集合,类似于Java的double。没有整型数据结构。此外还包含三个特殊的值: NaNInfinity-Infinity
  • String 类型的值是有穷个Unicode字符的集合。必须用 '" 括起来。

对象类型

javascript作为一门 脚本语言 ,本身功能十分精简,很多功能(文件读写、网络等)都是由宿主环境提供。宿主环境与javascript语言的桥梁是对象,宿主环境通过提供一系列符合javascript语法的对象,提供各种各样的功能。

在 javascript面向对象编程 这篇文章(如果你不知道prototype是什么,强烈建议看看这篇文章)里,我多次强调了 对象在javascript中就是一系列的键值对 ,就像Java中的HashMap一样,不过,javascript中对象的属性可以有一些描述符(property descriptor),这在HashMap中是没有的。

属性描述符

属性描述符分为两类:

  • 数据描述符(data descriptor),包含一系列boolean值,用以说明该属性是否允许修改、删除。
  • 访问描述符(accessor descriptor),包含get与set函数。

这两种描述符都是对象,它们都拥有下面两个boolean属性:

  • configurable 用以指定该描述符是否允许修改、删除。默认为false。
  • enumerable 用以指定在遍历对象(使用 for…in循环 或 Object.keys方法 )的属性时,是否访问该属性。默认为false。

除了上面这两个共有属性外,数据描述符还有下面两个属性:

  • value 用以指定该属性的值,默认为undefined
  • writable 用以指定该属性的值是否允许改变该属性的值,默认为false

访问描述符还有下面两个属性:

  • get 用以指定访问该属性时的访问器(getter,本质是个函数),该访问器的返回值为该属性的值。默认为undefined
  • set 用以指定访问该属性时的赋值器(setter,本质是个函数),该赋值器的接受一个参数。默认为undefined

我们可以使用 Object.defineProperty 来设置对象的属性描述符。例如:

// using __proto__
Object.defineProperty(obj, 'key' , {
__proto__: null , // no inherited properties
value : 'static' // not enumerable
// not configurable
// not writable
// as defaults
});

通过上面这个例子可以看出,描述符具有继承的特点,我们这里显式的把描述符对象的 __proto__ 设为 null ,就避免了从 Object.prototype 中继承相应属性。当然我们也可以显式地设置描述符的所有属性:

// being explicit
Object.defineProperty(obj, 'key' , {
enumerable: false ,
configurable: false ,
writable: false ,
value : 'static'
});

这样的效果和第一段代码的效果是一样的。

下面再举一个访问描述符的例子:

var bValue = 38 ;
Object.defineProperty(obj, 'key' , {
get : function () { return bValue; },
set : function (newValue) { bValue = newValue; },
enumerable: true ,
configurable: true
});

需要注意的是,不能混淆了访问描述器与数据描述器。下面这样写是错误的:

// You cannot try to mix both:
Object .defineProperty(obj, 'conflict' , {
value: 0x9f91102 ,
get: function () { return 0xdeadbeef ; }
});
// throws a TypeError: property descriptors must not specify a value
// or be writable when a getter or setter has been specified

typeof

如果想在运行时获知某变量的类型,可以使用typeof操作符。typeof的返回值如下表:

JavaScript 中的数据类型

其中有一处需要注意,那就是 typeof null == "object" ,按照 ECMAScript 5.1 标准, Null 类型应该是个基本类型,为什么这里返回 object 呢?原因是这样的:

在Javascript的第一版实现中,javascript中的值是用一个类型标志(type tag)和一个实际值这样的结构表示的,对象的类型标志为0,null在C语言中表示NULL指针(0x00),所以null的类型标志就为0了。

参考

  • A Survey of the JavaScript Programming Language
  • Object.defineProperty
  • typeof
  • The history of “typeof null” (需翻墙)
正文到此结束
Loading...