首先,就hax 、月影和爱民对样章中的技术问题进行指正表示感谢,刚才上来时看了一下爱民的理性分析,感染了我,我应该做一下理性的回应,以对大家的关心表示敬意,同时也想就个别问题与JavaScript专家们切磋、沟通一下。
由于问题很多,我还是按着hax提出的问题,以及爱民分析的思路进行梳理,有些问题可能来不及回应,等回头补上。
这个作用域链(Box.prototype.constructor.constructor.prototype)很长,长得几乎能够让
人背过气,它 是什么玩意?
“作用域(链)”通常是一个运行期的概念。在静态讨论它时,通常是以代码块(代码上下文位置)来做参考的。而作者列出了一个长长的属性存取,又说它是“作用域(链)”,是概念上出了问题。作者举的这个例子,只能用于讨论原型继承方面的一些问题,与作用域无关。
“作用域(链)”通常是一个运行期的概念。这话没错,我列出的一个长长的属性存取,实际上它是原型域链,爱民后半句也提到了,原型域与原型域链在JavaScript中是一个很重要的概念,不知道二位专家认可吗?就这个话题咱们还可以继续讨论,我当时在写作时,也是考虑到这个JS特性才这样写。是否正确,还有待专家指正。
从底层来看对象,对象就是一系列属性的集合,这与其他语言中的列表结构类似。
“对象=属性包”,这个简单而生动的定义是anders说过的,我也常常拿来讲给别人听。所以这里没错。但hax用红色标出了“列表”两个字,他的意思是存疑于:“对象”与“列表”有什么关系吗?这还真是个问题。
1、在Delphi里面,TList与TStringList是两件事。TList是指针列表,没有“名-值”概念,所以TList不适于跟“对象”来做比较,反倒是说“对象跟TStringList有些类似”是可以的。但是,作者在书里没有指出“其它语言”是哪一种,所以这里就不好讲了。
2、再说,以《数据结构》这样的教材为例,列表也是没有“名-值”概念的,所以不适宜与“对象”来比较。
3、其三,作者原意是“从底层来看对象”,那就整个儿不对了。底层来看对象,对象其实不是“列表”这种结构的。(在SpiderMonkey的实现中,)它是表没错,但是是链表。
我在写这句话时,没有爱民想得这样细微,所以缺乏严谨。本意是:考虑到对象和列表都是典型的数据类型,它们具有相似的结构特征,同时初学者对于列表的概念比较容易理解,所以就顺手拿过来进行比拟了。“从底层来看对象”,是想说明从数据基本特性来说,不过很不严谨,汗颜,向二位致敬。
另外,说明一下,列表数据的结构还是比较灵活的,以前看过这方面的深入讲解,一时找不到了,等找到了再补上。爱民就列表数据结构的分析还仅是针对特定语言。这个问题,等我找到资料后再讨论。
例如,a 引用 o,但是如果 o 的值发生了变化,则 a 就不指向 o 了
1、一般来说,“a引用o”,在代码上的含义是:
a.x = o;
2、接下来,作者说,“如果 o 的值发生了变化”,那么代码上的含义是:
o = y;
或
o.mmm = nnn;
3、再接下来,作者说,“则 a 就不指向 o 了”。请问,作者的陈述正确吗?
(1)其实a从来就没有指向过o。因为a与o并不是同一个东西,如果a指向o,就是同一个东西的引用关系了。
(2)如果说a.x引用指向了o,那么上述的过程发生后,a.x的引用关系其实并没有发生变化。
综上:作者表达确有问题。
“a引用o”和“a.x = o;”不是一会事儿吧?我的理解是“a = o;”, 而a.x = o所表示的是对象属性的引用,不是一个概念吧?期待二位具体解释一下。当然,后面两个问题都是建立在这个观点基础之上,先就不说了。
各家浏览器的JavaScript 引擎也各不相同,分 歧最明显的就是 DOM实现部分。
老实说,你讨论JavaScript就成了,把DOM拉进来做什么?DOM、CSS与JS三者是同一层级上的东西,按你的说法,却是JS包括了DOM——那么ECMA Script也该对DOM做标准化了?
JS和DOM是不分家的,虽然他们是独立的模块,但是两者依存关系非常严重,至少在浏览器中是这样的,所以大家的概念都把JS与DOM混淆在一起。
HTML、CSS与JS三者应该是同一层级上的东西。
ECMA Script仅是一个标准规则,而DOM也是一个标准规则,浏览器在具体应用时,是把他们融合在一起了,这样说可能不严谨,但习惯上是这样认为的。
各家浏览器对于JavaScript脚本的分歧主要在于DOM,而对于JavaScript核心方面基本上保持一致,当然也存在差异。
计算需要对象,于是就产生了数据。
l 计算需要效率,于是就产生了类型。
l 计算需要控制,于是就产生了变量。
第一句,如果你不打算与“Object”混淆。建议改成“计算需要目标”。
第二句,类型,与效率有必然关系吗?
第三句,“计算的控制”,通常就成逻辑了。变量或变量名,其实最早的概念是叫“引用数”的。它不过是一个标识。所以,如果说“计算目标(或被计算对象)需要标识,所以产生了变量”,大概更好。
“计算需要目标”,嗯,这样更科学,呵呵。
好像64位的系统比32位的系统更高效。不然微软不断向高位系统发展,这个问题应该是这样,还有待争论。
如果说“计算目标(或被计算对象)需要标识,所以产生了变量”,大概更好,嗯,我当时考虑的要兼顾易读、易解,没有过于在技术上死扣,不过还是很谢谢爱民这种严谨、认真的精神。在下应虚心学习。
而类型正是数据的单位,通俗地说就是计算机指令一次可以操作的数据块大小。
例如,双字节一次可以操作 32 位数据,……
老实说,这段太大了。我没读完。但作者说“如果没有各种数据类型,则计算机只有一个单位(即字节)……”,这是不负责任的。因为“字节”也是数据类型。放弃所有数据类型,以“纯粹的计算机”来讨论,则唯一单位是“位(bit)”。至于,如果要讨论到计算机的原理,以某类确定的机型而言,可以以总线类型来作为基本类型——这包括了寄存器、总线在操作位数上的一致性。例如32位机器,则可以说“32位整型”或者“双字(DWORD)”为基本类型。
又,正好又看到上文中的一个小错误“双字节一次可以操作 32 位数据”,这里应该是“16位”才对哦。
这里是误解了,我的本意是说明,如果没有语言中的各种数据类型概念,不过还是很感谢爱民指正。其中“双字节一次可以操作 32 位数据”,这里应该是“16位”,是的,我口误了,汗~
最后,容我辩解一下:在追求技术严谨性和通俗性时,我多选择了后者,所以很多忽略了技术的严谨性,很多语言经不起专家的推敲,实在抱歉。不过,我是这样认为的:把技术写得更通俗、随和一些,往往读者更喜欢阅读。正如,读者爱买《大话设计模式》,而敬畏《设计模式》一样。
面向对象就是对数据的一种抽象
面向对象是编程方法,而不是数据抽象。把前面的“面向”去了就对了。
嗯,致敬。
弱类型……当然这也是以牺牲开发速
度和效率为代价的,所以它成不了大气候
认识问题吧。不过不知道作者是如何比较得出这样的结论的。
这个观点来源于外文资料。不过,JavaScript确实如此,仅适合做些小工作,在关键应用上,它的执行效率是必须顾虑的问题。
更为有趣的是:浮点数是以字符串的形式进行存储的。
css8错了,除了在文本代码里面,没这么存储的。可以建议看看IEEE标准,或者看引擎源代码。
这个观点也是参考过一份资料,等我再核实一下。
一般不建议大家使用八进制数值直接量。因为很多时候,JavaScript 会误解析为十进制数值。
这种建议无意义的。用不用,是应用说了算。没有无聊到非得拿8进制来做事。再说,js里面,还有13、15、25进制的,有必要一一建议吗?
这句话是在上下文中说的。
同时,8进制,有时会用到,而13、15、25进制基本上用不上。
如果字符串包含在双引号中,则字符串内可以包含单引号。反之,就不行了,但是在 VBScript 中就可以在单引号中包含双引号
“反之,就不行了”,这个你写个测试代码先?
写这话之前,我是碰到过这样的问题,不然也不会提及这个问题。代码忘记了,等我想一想。
布尔型(Boolean)……所占据的空间也是最小的(仅有 1 个字节)
这个……仍然是4个字节。其实——道理上来说,还不止4个字节。你最好看看引擎源码。
待我再琢磨一下。
在对象中,当为属性设置值为 null 时,会提醒JavaScript 回收它们,无用也即无存在的价值,所以赋值 null 就等于判变量死刑(即删除变量)。
1、你前面在说“对象属性置null”,后面在说“变量置null“。这是两回事呀,二者没有推论关系的。
2、变量如果是指标识符,那么,“删除变量”这样的事情从来就不会发生。
3、很遗憾,全局变量不会被回收。因为保不齐什么时候在某个函数里面会来一个eval()语句,然后就访问到某个全局变量的标识符了。所以置null最多回收它的内存占用,但变量还是在的。
4、局部变量,是随闭包回收而回收的。
分析在理。
JavaScript 数组的结构比较固定,仅支持定义一维数组,虽然这简化了数组操作,但是
扩展性比较差,你 不能够使用JavaScript 定义多维数组。这 种固化的结构也显示了JavaScript
语言的柔弱性
你的“柔弱性”判断是有问题的,我看不出推论的依据何来。另外,许多多维数组的特性,可以通过交错数组来得到。这个在《程序设计语言》这本书里给出过解释。所以不必认为JS没有多维数组是“多么大的牺牲”。
表述的意思不同。
如果属性值是函数,则该属性就成为对象的方法,读取这个特殊的属性值时,就必须附加小括号运算符
“读取这个特殊的属性值时”,其实不需要加括号运算符。反倒是“执行/调用”它时,才需要加的。这个,作者在概念的陈述上,真的不严谨。
是的。
如果读者分析Google 网站的 JavaScript 程序,变量命名非常简洁,一般都为 1 或 2 个字母组成,这样做能够提高开发速度,便于书写
你能下载的Google网站的代码,是混淆过的。
如果你真要看Google的代码,你应该看看他们在Google map上公开的那几份。你就知道,他们的变量命名习惯不是你说的这样了。
我说的就是它的优化后代码。
[quote]如果我们为变量a 赋值为 null,则 JavaScript 垃圾回收器就知道这个变量也没有
用,于是把这个变量视为垃圾一并进行回收(栈区),也就是说,如果一个变量、属性、元
素或对象被赋值为 null,也就意味着它们是无用的垃圾了
1、回收与所谓“栈区”无关。
2、变量回收问题,前面讲过了。
3、属性不能被置null回收的。但可以通过delete语句来回收。
4、元素(array element)同上述第三条;而且数组元素可以通过splice()来删除和回收。
5、对象赋值为null?与变量同义吧?有必要区分么?
……[/quote]
回收栈区空间。
回收对象,等于回收了它的所有成员。
还有未回应的问题,等我仔细阅读后,再与你们沟通一下。
最后再次向几位专家的敬业精神表示敬意。
谢谢!