英文原文:For modern development Javascript indeed is a s?h?i?t? dissapointing language
我很抱歉,但 Crockford 就是坚持这么写的(I’m sorry, but the Crockford arguments do not cut it.)。
Javascript 在很多方面都烂透了,而且还极其无趣。我就纳了闷了,大家为啥都义无返顾、群情激奋的跳进 Node 学习的大军里。是!Node 是比 Ruby 快,Node 是基于事件模型处理的,但让我无法理解的是——一些人动不动就想把自己的程序用 Node 重构一下,过过脑子行吗!
Javascript 的继承,深拷贝问题,不是定义一个新的 ECMA 标准就能解决的,不是套个漂亮的语法外壳(比如 CoffeeScript)就能搞定的,不是用 require 实现个标准化或者引入 classes 就可以万事大吉的,ECMA 语言里不是有个引入 classes 的 ActionScript 吗!那玩意跟 Javascript 一样屎,只要大家继续用它,PHP 框架的现状就是 JS 的未来——一堆一堆的人前赴后继,日以继夜的为这坨屎一样的语言搭框架、写工具。
我来说一下为什么 Javascript 糟糕,当然了,它也有好的方面。 但是问题就是太不实用,比如说原型继承(prototypal inheritance)就限制颇多——因为这玩意说白了就是 function override,还有就是那句:“万物皆 function” 也是相当的废柴——因为 function 不是一个对象,也不能当做数据结构来承载数据。
其实真正的吐槽才刚刚开始,随便列几个吧:
JS 的调用属性
看这个屎一样的设计,回顾过去,咱们很难苛责语言的设计人员,因为它们可能处于性能考虑。再者,如果不习惯消息-传递机制的语言的话,你会觉得“怎么一些属性可以被调用而另外一些就不可以呢”!
哈希对象对于 stable 键不可用
对象和哈希的混合不是一个好点子,因为它违反了对象可以拥有 metadata 的前提,metadata 允许我们建立基本类型系统或者至少各种类型的 introspection。
函数对象对于类型系统不可用,因为一个对象不携带任何类型信息
这可是大事,Ruby 的世界里也是这样,感觉所有的东西都在像鸭子一样快乐的嘎嘎叫。我们经常用 Object$class 来获取对象信息,下面是给 HTML 元素加样式的标准的流程:
<div class='<%= model.class %>' id='<%= [model.class, model.id].join %>' >…
在 JS 里是不可能的,因为只有'Object','function'和原始类型才有类型信息。
到处是 Null
不小心用错了一个常量。
MyApp.SYNC <i>
// should have been MyApp.SYNC_FETCH</i>
任何事情都不会发生,因为对象是 hashes,而且 js 给常量默认为0。 带着错误 key 的常量将会是 undefined,而且还会渗透到被调用函数中,等出了事,慢慢跟踪 debug 去吧。
回调的深渊
JS 缺少合适的 deferred 功能,不是多线程,就得靠事件化执行。你的调用会散落在各个事件回调中,代码都完事了,回调还在那执行呢,比如,JS 干下面这个是就费劲。
var res = await AjaxReq.fetch ('/long-request') // because you are waiting for a result, here the runtime would
// schedule event handling, DOM redraws and whatever else it can
// squeeze in while you await
res.name
// this will be only executed once res is available
因为你在等一个结果,就在等待的这会,runtime 完全可以进行事件处理、DOM 重绘、干啥都行。
res.name —— 等 res 可以使用的时候在去执行 res.name 的操作。
当然了,JS 社区做了跟 PHP 社区一直以来一样的事情——给 Javascript 这坨屎擦屁股,怎么擦呢?用更多的回调,好点的,就是回调链
when (<ERMAGHERD RIDICULOUSLY LONG CALLBACK> // 48 lines of code down
) .then (<HOLYSHIT WHEN WILL THIS BE OVER>
// 23 lines down
) .then (<GIVE ME SOME COFFEE ALREADY>)
一般情况下,加入一个 wait primitive 就在获取结果的等待过程中控制 events。
专业一点的做法就是啥玩意咱都异步,现实是你写的代码 80% 都是同步的,因为程序里 80% 干的都是——个操蛋的事情跟另外一个操蛋的事情一起搞,而且你需要它俩都它妈的完事了才行。
可怕的异常处理机制
异常处理在 JS 中机器可怕,一般形式——你可以查看调用堆栈(一堆匿名函数和好点的名字的函数),你可看到错误信息,我就提两个经常碰到的错误:
undefined is not a function cannot call property 'xyz' of undefined
这都拜 Javascript 中“函数(泥煤)对象”所赐,根本没有方法定义——它们只有属性,JS 运行时永远没有办法知道函数对象有没有方法可以被调用,或者某个属性名称——它就认为你的哈希键不存在。
我记得 Ruby 社区里的人抱怨 Ruby 的回溯和错误消息机制不好用,Rubinius 就给解决了。在泥煤的 Javascript 里,你知道错误消息特别乱吗?因为有你想得到和使用的两个最最基本、最最重要的异常 NameError 和 NoMethodError 都有可能,这在其它语言里都是不能理解的,但 Javascript 语言就这么马马虎虎的用起来了。
不可否认,functions 是亮点,原型也是好东西,但是如果你想建立一个稍微复杂的 JS 应用,你就得这么写:
var cv = Marionette.CollectionView.extend ({ itemView: MyApp.Views.WidgetView; });
如果“MyApp.Views.WidgetView 还没有定义”,你会得到啥错误?“undefined is not a function”。当然!你什么时候会得到呢?当 CollectionView 想要实例化你的视图的时候,而不是当你定义变量 cv 的时候,你会忐忑好几分钟,直到你明白了这错误是哪里导致的。
这是为啥呢?因为所有都是 hash, 而且这个语言不能做任何形式的 introspection。
还有一个困扰我的事就是,有些大哥居然从 Ruby 转战 Node,还赞 Node 是个好东西。Node 也许是好宝贝,但是想想它内部运行着屎一样的 Javascript 语言,我就由衷地想退避三舍。
这么说吧,JS 一日不好用,我便一日不会用 Node,谢谢。
我理解有一些人想跳出 MRI 架构,投身 Node,很简单啊——你不会说日语, 所以你舔个脸说日语很难学,话撂这,你在 MRI 上的有精进的机会也它妈趋近于 0。
JS 是屎,但凡我们有那么一丝丝的担当,就该尽自己的绵薄之力要么让它寿终正寝,要么帮助它更上一层楼,天天在那沾沾自喜对它的发展没有一点帮助,CoffeeScript 做的还远远不够。
更新:看这里,我不是一个人在战斗。
译者注:julik live 博主后来把标题改为了“For modern development Javascript indeed is a s?h?i?t? dissapointing language”。另外,他博客页脚不美观,占用空间过大,在原文评论中被很多读者吐槽了。当然了,也有热心网友在帮他出主意了。
翻译: 伯乐在线 - 黄利民 译文链接: http://blog.jobbole.com/50671/