关于数组(array)、对象(object)、函数(function)和正则表达式,我们通常喜欢以常量的形式来创建它们。实际上,使用常量和使用构造函数的效果是一样的(创建的值都是通过封装对象来包装)。
如前所述,应该尽量避免使用构造函数,除非十分必要,因为它们经常会产生意想不到的结果。

3.4.1 Array(..)

var a = new Array( 1, 2, 3 );
a; // [1, 2, 3]
var b = [1, 2, 3];
b; // [1, 2, 3]

构造函数Array(..) 不要求必须带new 关键字。不带时,它会被自动补上。
因此Array(1,2,3) 和new Array(1,2,3) 的效果是一样的。

Array 构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度(length),而非只充当数组中的一个元素。
这实非明智之举:一是容易忘记,二是容易出错。
更为关键的是,数组并没有预设长度这个概念。这样创建出来的只是一个空数组,只不过它的length 属性被设置成了指定的值。
如若一个数组没有任何单元,但它的length 属性中却显示有单元数量,这样奇特的数据结构会导致一些怪异的行为。而这一切都归咎于已被废止的旧特性(类似arguments 这样的类数组)。

3.4.2 Object(..)、Function(..) 和RegExp(..)

同样,除非万不得已,否则尽量不要使用

Object(..)/Function(..)/RegExp(..):

var c = new Object();
c.foo = "bar";
c; // { foo: "bar" }
var d = { foo: "bar" };
d; // { foo: "bar" }
var e = new Function( "a", "return a * 2;" );
var f = function(a) { return a * 2; }
function g(a) { return a * 2; }
var h = new RegExp( "^a*b+", "g" );
var i = /^a*b+/g;

在实际情况中没有必要使用new Object() 来创建对象,因为这样就无法像常量形式那样一次设定多个属性,而必须逐一设定。

构造函数Function 只在极少数情况下很有用,比如动态定义函数参数和函数体的时候。不要把Function(..) 当作eval(..) 的替代品,你基本上不会通过这种方式来定义函数。

强烈建议使用常量形式(如/^a*b+/g)来定义正则表达式,这样不仅语法简单,执行效率也更高,因为JavaScript 引擎在代码执行前会对它们进行预编译和缓存。与前面的构造函数不同,RegExp(..) 有时还是很有用的,比如动态定义正则表达式时:

var name = "Kyle";
var namePattern = new RegExp( "\\b(?:" + name + ")+\\b", "ig" );
var matches = someText.match( namePattern );

上述情况在JavaScript 编程中时有发生,这时new RegExp("pattern","flags") 就能派上用场。

3.4.3 Date(..) 和Error(..)

相较于其他原生构造函数,Date(..) 和Error(..) 的用处要大很多,因为没有对应的常量形式来作为它们的替代。
创建日期对象必须使用new Date()。Date(..) 可以带参数,用来指定日期和时间,而不带参数的话则使用当前的日期和时间。
Date(..) 主要用来获得当前的Unix 时间戳(从1970 年1 月1 日开始计算,以秒为单位)。该值可以通过日期对象中的getTime() 来获得。
从ES5 开始引入了一个更简单的方法,即静态函数Date.now()。
如果调用Date() 时不带new 关键字,则会得到当前日期的字符串值。其具体格式规范没有规定,浏览器使用"Fri Jul 18 2014 00:31:02 GMT-0500 (CDT)"这样的格式来显示。

构造函数Error(..)(与前面的Array() 类似)带不带new 关键字都可。
创建错误对象(error object)主要是为了获得当前运行栈的上下文(大部分JavaScript 引擎通过只读属性.stack 来访问)。栈上下文信息包括函数调用栈信息和产生错误的代码行号,以便于调试(debug)。
除Error(..) 之外, 还有一些针对特定错误类型的原生构造函数, 如

EvalError(..)、 RangeError(..)、 ReferenceError(..)、 SyntaxError(..)、TypeError(..) 和URIError(..)

这些构造函数很少被直接使用,它们在程序发生异常(比如试图使用未声明的变量产生ReferenceError 错误)时会被自动调用。

3.4.4 Symbol(..)

ES6 中新加入了一个基本数据类型 ——符号(Symbol)。符号是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名。该类型的引入主要源于ES6 的一些特殊构造,此外符号也可以自行定义。
符号可以用作属性名,但无论是在代码还是开发控制台中都无法查看和访问它的值,只会显示为诸如Symbol(Symbol.create) 这样的值。
ES6 中有一些预定义符号,以Symbol 的静态属性形式出现,如

Symbol.create、Symbol.
iterator 等

可以这样来使用:

obj[Symbol.iterator] = function(){ /*..*/ };

我们可以使用Symbol(..) 原生构造函数来自定义符号。但它比较特殊,不能带new 关键字,否则会出错:

var mysym = Symbol( "my own symbol" );
mysym; // Symbol(my own symbol)
mysym.toString(); // "Symbol(my own symbol)"
typeof mysym; // "symbol"

var a = { };
a[mysym] = "foobar";

Object.getOwnPropertySymbols( a );
// [ Symbol(my own symbol) ]

虽然符号实际上并非私有属性(通过Object.getOwnPropertySymbols(..) 便可以公开获得
对象中的所有符号),但它却主要用于私有或特殊属性。很多开发人员喜欢用它来替代有下划线(_)前缀的属性,而下划线前缀通常用于命名私有或特殊属性。
符号并非对象,而是一种简单标量基本类型。

摘自:《你不知道的javascript》中卷


发表评论

电子邮件地址不会被公开。 必填项已用*标注