深入理解JavaScript系列(18):面向对象编程之E(3)


var getClass = Object.prototype.toString;
 
Object = Number;
 
var foo = new Object;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"
 
var bar = {};
 
// Rhino, SpiderMonkey 1.7中 - 0, "[object Number]"
// 其它: still "[object Object]", "[object Object]"
alert([bar, getClass.call(bar)]);
 
// Array也是一样的效果
Array = Number;
 
foo = new Array;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"
 
bar = [];
 
// Rhino, SpiderMonkey 1.7中 - 0, "[object Number]"
// 其它: still "", "[object Object]"
alert([bar, getClass.call(bar)]);
 
// 但对RegExp,字面量的语义是不被改变的。 semantics of the literal
// isn't being changed in all tested implementations
 
RegExp = Number;
 
foo = new RegExp;
alert([foo, getClass.call(foo)]); // 0, "[object Number]"
 
bar = /(?!)/g;
alert([bar, getClass.call(bar)]); // /(?!)/g, "[object RegExp]"

正则表达式字面量和RegExp对象

注意,下面2个例子在第三版的规范里,正则表达式的语义都是等价的,regexp字面量只在一句里存在,并且再解析阶段创建,但RegExp构造器创建的却是新对象,所以这可能会导致出一些问题,如lastIndex的值在测试的时候结果是错误的:

复制代码 代码如下:


for (var k = 0; k < 4; k++) {
  var re = /ecma/g;
  alert(re.lastIndex); // 0, 4, 0, 4
  alert(re.test("ecmascript")); // true, false, true, false
}
 
// 对比
 
for (var k = 0; k < 4; k++) {
  var re = new RegExp("ecma", "g");
  alert(re.lastIndex); // 0, 0, 0, 0
  alert(re.test("ecmascript")); // true, true, true, true
}


注:不过这些问题在第5版的ES规范都已经修正了,不管是基于字面量的还是构造器的,正则都是创建新对象。

关联数组

各种文字静态讨论,JavaScript对象(经常是用对象初始化器{}来创建)被称为哈希表哈希表或其它简单的称谓:哈希(Ruby或Perl里的概念), 管理数组(PHP里的概念),词典 (Python里的概念)等。

只有这样的术语,主要是因为他们的结构都是相似的,就是使用“键-值”对来存储对象,完全符合“关联数组 ”或“哈希表 ”理论定义的数据结构。 此外,哈希表抽象数据类型通常是在实现层面使用。

但是,尽管术语上来描述这个概念,但实际上这个是错误,从ECMAScript来看:ECMAScript只有一个对象以及类型以及它的子类型,这和“键-值”对存储没有什么区别,因此在这上面没有特别的概念。 因为任何对象的内部属性都可以存储为键-值”对:

复制代码 代码如下:


var a = {x: 10};
a['y'] = 20;
a.z = 30;
 
var b = new Number(1);
b.x = 10;
b.y = 20;
b['z'] = 30;
 
var c = new Function('');
c.x = 10;
c.y = 20;
c['z'] = 30;
 
// 等等,任意对象的子类型"subtype"

此外,由于在ECMAScript中对象可以是空的,所以"hash"的概念在这里也是不正确的:

复制代码 代码如下:


Object.prototype.x = 10;
 
var a = {}; // 创建空"hash"
 
alert(a["x"]); // 10, 但不为空
alert(a.toString); // function
 
a["y"] = 20; // 添加新的键值对到 "hash"
alert(a["y"]); // 20
 
Object.prototype.y = 20; // 添加原型属性
 
delete a["y"]; // 删除
alert(a["y"]); // 但这里key和value依然有值 – 20

请注意, ES5标准可以让我们创建没原型的对象(使用Object.create(null)方法实现)对,从这个角度来说,这样的对象可以称之为哈希表:

复制代码 代码如下:


var aHashTable = Object.create(null);
console.log(aHashTable.toString); // 未定义


此外,一些属性有特定的getter / setter方法​​,所以也可能导致混淆这个概念:

复制代码 代码如下:


var a = new String("foo");
a['length'] = 10;
alert(a['length']); // 3

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgfgzd.html