锁定老帖子 主题:JavaScript内核系列 第5章 数组
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-04-26
abruzzi 写道 另外谢谢weiqingfei这位朋友的支持,希望你再接再厉,这样这个系列的质量才可以更好。
我觉得能静下心来,认认真真的做,并且做完一件事是值得尊敬的。佩服你,希望能坚持到底。 |
|
返回顶楼 | |
发表时间:2010-04-26
最后修改:2010-04-26
abruzzi 写道 zhouyrt 写道 呵,数组的数字索引看起来像其它语言的索引,但实际上它会隐式的转换成字符串。亦可参考 http://snandy.iteye.com/blog/284805 http://snandy.iteye.com/blog/407351 嗯,不错,用一个for..in就可以看到了。JavaScript的数组本质上还是键-值这样的形式,而不是一个连续的内存块(C/Java中都是连续的),而是一个散列表。 其实正好相反。在array['1']=''时,javascript会把它当翻译成array[1],所以用array[1],和array['1']都能访问到,而且array.length会变成2。 但是如果用array['1a']='',那么你只能用array['1a']来访问,因为1a被当做数组对象的一个属性而非数组的内容,所以array的length是0,同时在array的tostring和jion等方法时1a是不会参与的。 至于 for in 语句中只是对于array来说会在array中的内容迭代完会把对象中的属性也迭代出来而已,并不是说1a就是数组的内容 |
|
返回顶楼 | |
发表时间:2010-04-26
Lunatica 写道 abruzzi 写道 zhouyrt 写道 呵,数组的数字索引看起来像其它语言的索引,但实际上它会隐式的转换成字符串。亦可参考 http://snandy.iteye.com/blog/284805 http://snandy.iteye.com/blog/407351 嗯,不错,用一个for..in就可以看到了。JavaScript的数组本质上还是键-值这样的形式,而不是一个连续的内存块(C/Java中都是连续的),而是一个散列表。 其实正好相反。在array['1']=''时,javascript会把它当翻译成array[1],所以用array[1],和array['1']都能访问到,而且array.length会变成2。 但是如果用array['1a']='',那么你只能用array['1a']来访问,因为1a被当做数组对象的一个属性而非数组的内容,所以array的length是0,同时在array的tostring和jion等方法时1a是不会参与的。 至于 for in 语句中只是对于array来说会在array中的内容迭代完会把对象中的属性也迭代出来而已,并不是说1a就是数组的内容 嗯,我觉得你的理解更有道理一些,我再做一些测试,谢谢! |
|
返回顶楼 | |
发表时间:2010-04-27
php的精华在数组,js也有点像
|
|
返回顶楼 | |
发表时间:2010-04-27
最后修改:2010-04-27
weiqingfei 写道 abruzzi 写道 weiqingfei 写道 引用 另一个与其他语言的数组不同的是,字符串也可以作为数组的下标(事实上,在JavaScript的数组中,数字下标最终会被解释器转化为字符串,也就是说,所谓的数字下标只不过是看着像数字而实际上是字符的属性名),比如:
这个是Object最基本的特性,Array源于Object,自然有这个特性,这个不能说是javascript数组特殊的地方。 你的意思我理解,我想表达的是,这个特性是JavaScript数组区别于其他语言的数组的,并不是JavaScrpt数组区别于JavaScript对象的。 Array作为Object,接受key-value序列赋值时,只有当key可转为正整数,才有可能对length进行修改。 比如 var a=[]; a[0] = 0; a["1"] = 1; a[new Number(2)] = 2; a[new String(3)] = 3; a[new Object(4)] = 4; var MyObj = function(value){ this.value = value; this.toString = function(){ return this.value; } } a[new MyObj(5)] = 5; 不知道你用的是什么解释器?我使用的解释器器是Rhino,可以设置的,我试了下你的例子。 不知为什么,javascript的“数组”让我觉得一阵阵恶心。 嗯,例子就是演示使用这样形式的下标,是可以给数组赋值并重新计算length的, 由此也可以大概猜想一下Array对象的内部实现。 大概的看了一下rhino关于Array部分的实现,和我猜想的差不多。 源文件org/mozilla/javascript/ScriptRuntime.java中1517行方法 public static Object setObjectElem(Scriptable obj, Object elem, Object value, Context cx) { if (obj instanceof XMLObject) { XMLObject xmlObject = (XMLObject)obj; xmlObject.ecmaPut(cx, elem, value); return value; } [b] [color=red]String s = toStringIdOrIndex(cx, elem);[/color][/b] if (s == null) { int index = lastIndexResult(cx); ScriptableObject.putProperty(obj, index, value); //属性elem可以作为index } else { ScriptableObject.putProperty(obj, s, value); //属性elem为其它 } return value; } 再看看toStringIdOrIndex方法 static String toStringIdOrIndex(Context cx, Object id) { if (id instanceof Number) { //如果属性为数字 double d = ((Number)id).doubleValue(); int index = (int)d; if (index == d) { storeIndexResult(cx, index); return null; } return toString(id); } else { String s; if (id instanceof String) { //如果属性为字符串 s = (String)id; } else { s = toString(id); //如果属性为其他,用toString方法得到其字符串值 } long indexTest = indexFromString(s); //这个方法判断这个字符串是否可以做index if (indexTest >= 0) { storeIndexResult(cx, (int)indexTest); return null; } return s; } } 再看一下toString方法 public static String toString(Object val) { for (;;) { if (val == null) { return "null"; } if (val == Undefined.instance) { return "undefined"; } if (val instanceof String) { return (String)val; } if (val instanceof Number) { // XXX should we just teach NativeNumber.stringValue() // about Numbers? return numberToString(((Number)val).doubleValue(), 10); } if (val instanceof Scriptable) { val = ((Scriptable) val).getDefaultValue(StringClass); if (val instanceof Scriptable) { throw errorWithClassName("msg.primitive.expected", val); } continue; } return val.toString(); //如果只是一般的object,就是用其toString方法的返回值, } //这个也就是我例子里所举的那个自定义对象的情况 } 调用ScriptableObject.putProperty(obj, index, value); 实质上调用的是NativeArray.put(int index, Scriptable start, Object value)方法 引用 public void put(int index, Scriptable start, Object value) { if (start == this && !isSealed() && dense != null && 0 <= index && (denseOnly || !isGetterOrSetter(null, index, true))) { if (index < dense.length) { dense[index] = value; if (this.length <= index) this.length = (long)index + 1; return; } else if (denseOnly && index < dense.length * GROW_FACTOR && ensureCapacity(index+1)) { dense[index] = value; this.length = (long)index + 1; return; } else { denseOnly = false; } } super.put(index, start, value); //这儿调用了super的方法,实际上上面的例子是没有走到这儿的。 if (start == this) { // only set the array length if given an array index (ECMA 15.4.0) if (this.length <= index) { // avoid overflowing index! this.length = (long)index + 1; } } } 看来在rhino的实现中,可作为数组属性,和其他属性是分开管理的。 |
|
返回顶楼 | |
发表时间:2010-04-27
weiqingfei 写道 weiqingfei 写道 abruzzi 写道 weiqingfei 写道 引用 另一个与其他语言的数组不同的是,字符串也可以作为数组的下标(事实上,在JavaScript的数组中,数字下标最终会被解释器转化为字符串,也就是说,所谓的数字下标只不过是看着像数字而实际上是字符的属性名),比如:
这个是Object最基本的特性,Array源于Object,自然有这个特性,这个不能说是javascript数组特殊的地方。 你的意思我理解,我想表达的是,这个特性是JavaScript数组区别于其他语言的数组的,并不是JavaScrpt数组区别于JavaScript对象的。 Array作为Object,接受key-value序列赋值时,只有当key可转为正整数,才有可能对length进行修改。 比如 var a=[]; a[0] = 0; a["1"] = 1; a[new Number(2)] = 2; a[new String(3)] = 3; a[new Object(4)] = 4; var MyObj = function(value){ this.value = value; this.toString = function(){ return this.value; } } a[new MyObj(5)] = 5; 不知道你用的是什么解释器?我使用的解释器器是Rhino,可以设置的,我试了下你的例子。 不知为什么,javascript的“数组”让我觉得一阵阵恶心。 嗯,例子就是演示使用这样形式的下标,是可以给数组赋值并重新计算length的, 由此也可以大概猜想一下Array对象的内部实现。 大概的看了一下rhino关于Array部分的实现,和我猜想的差不多。 源文件org/mozilla/javascript/ScriptRuntime.java中1517行方法 public static Object setObjectElem(Scriptable obj, Object elem, Object value, Context cx) { if (obj instanceof XMLObject) { XMLObject xmlObject = (XMLObject)obj; xmlObject.ecmaPut(cx, elem, value); return value; } [b] [color=red]String s = toStringIdOrIndex(cx, elem);[/color][/b] if (s == null) { int index = lastIndexResult(cx); ScriptableObject.putProperty(obj, index, value); //属性elem可以作为index } else { ScriptableObject.putProperty(obj, s, value); //属性elem为其它 } return value; } 再看看toStringIdOrIndex方法 static String toStringIdOrIndex(Context cx, Object id) { if (id instanceof Number) { //如果属性为数字 double d = ((Number)id).doubleValue(); int index = (int)d; if (index == d) { storeIndexResult(cx, index); return null; } return toString(id); } else { String s; if (id instanceof String) { //如果属性为字符串 s = (String)id; } else { s = toString(id); //如果属性为其他,用toString方法得到其字符串值 } long indexTest = indexFromString(s); //这个方法判断这个字符串是否可以做index if (indexTest >= 0) { storeIndexResult(cx, (int)indexTest); return null; } return s; } } 再看一下toString方法 public static String toString(Object val) { for (;;) { if (val == null) { return "null"; } if (val == Undefined.instance) { return "undefined"; } if (val instanceof String) { return (String)val; } if (val instanceof Number) { // XXX should we just teach NativeNumber.stringValue() // about Numbers? return numberToString(((Number)val).doubleValue(), 10); } if (val instanceof Scriptable) { val = ((Scriptable) val).getDefaultValue(StringClass); if (val instanceof Scriptable) { throw errorWithClassName("msg.primitive.expected", val); } continue; } return val.toString(); //如果只是一般的object,就是用其toString方法的返回值, } //这个也就是我例子里所举的那个自定义对象的情况 } 调用ScriptableObject.putProperty(obj, index, value); 实质上调用的是NativeArray.put(int index, Scriptable start, Object value)方法 public void put(int index, Scriptable start, Object value) { if (start == this && !isSealed() && dense != null && 0 <= index && (denseOnly || !isGetterOrSetter(null, index, true))) { if (index < dense.length) { dense[index] = value; if (this.length <= index) this.length = (long)index + 1; return; } else if (denseOnly && index < dense.length * GROW_FACTOR && ensureCapacity(index+1)) { dense[index] = value; this.length = (long)index + 1; return; } else { denseOnly = false; } } super.put(index, start, value); //这儿调用了super的方法,实际上上面的例子是没有走到这儿的。 if (start == this) { // only set the array length if given an array index (ECMA 15.4.0) if (this.length <= index) { // avoid overflowing index! this.length = (long)index + 1; } } } 看来在rhino的实现中,可作为数组属性,和其他属性是分开管理的。 嗯,分析的很好,很认真,呵呵。 String s = toStringIdOrIndex(cx, elem); if (s == null) { int index = lastIndexResult(cx); ScriptableObject.putProperty(obj, index, value); //属性elem可以作为index } else { ScriptableObject.putProperty(obj, s, value); //属性elem为其它 } 以及这块: if (start == this) { // only set the array length if given an array index (ECMA 15.4.0) if (this.length <= index) { // avoid overflowing index! this.length = (long)index + 1; } } 就可以说明大部分问题了, 。 |
|
返回顶楼 | |
发表时间:2010-04-27
|
|
返回顶楼 | |
发表时间:2010-04-28
好几天没关注楼主的文章了,今天跟上。
|
|
返回顶楼 | |