返回首页 Cocos2D-x 从 C++ 到 JS 的进阶之路

JS 脚本语言的优势与一些问题

优势:

  1. 不需声明,甚至匿名方式原地定义。编码量少。 这一条在 C++ 中尤其明显,以绑定一个回调为例,需要声明,定义,调用绑定,三处代码。虽然 C++11 中支持 lambda 表达式,对于回调的写法有很大改进。但是其他地方依然蛋疼。

  2. 弱类型语言,一般情况下,不需关心实际类型。Debug 时除外。 在使用 C++ 这种强类型语言的开发中,尤其是写功能代码时,类型检查远不如想象中那么有用,很多时候反而是问题根源,编译不通过时,很大一部分时间是在对变量类型,由此还衍生出一些特殊技术手段,比如适配器模式等等。
    使用 JS 这种弱类型语言,只要接口名称能对上,那么在对象的函数被调用时就认为是正确的。简单说,只要长得像某一类型就行了,不需要必须是某一类型。
    C++11 中 auto 关键字也可以提升编码速度(和 JS 的 var 很类似,可以随时无脑输出),不过看了一下引擎附带的几个例子代码,好像有滥用 auto 的趋势。

  3. 脚本语言动态扩展能力强,可以不必构造很多临时类型和消息类型。 比如,在大型游戏中,全局使用消息机制时,C++ 可能用结构体,自定义类,或者我们以前直接丢J SON 对象过去。在 JS 里面就很简单了,直接扔 JSON 对象吧。 在运行时可以动态给一个对象添加函数和属性,而不需要重新构造新类和初始化。JSON 源自 JS,JSON 是天然的消息对象,非常合适。当然 JSON 有自身的缺点,访问父节点和兄弟节点不太方便。并且 JSON 的结构和二维表没法完全兼容,这是一直让策划和工具程序员头痛的一个问题。

  4. 语法灵活,可以支持各种编码方式。随机应变。 业界普遍认为面向对象在图像编程是最好的。但对于事件处理逻辑处理AI处理来说,面向对象则是罗嗦的要死。比如,我实在对观察者模式提不起兴趣,Qt 中的信号槽机制优雅的多。又比如我曾经做了一个 A* 算法代码,想改成好用的面向对象方式,发现很痛苦。
    JS 很灵活,适合什么样的编码方式,就用什么样的方式。

  5. 在语言级别天生集成了两种最有用的数据结构,向量和映射表。 记得在 KJava 时代,MIDP 的里面只有很少的数据结构,里面就有向量和哈西表。这两种是最为常用的。JS 在语言层面提供了支持,编码极其方便。

  6. 脚本语言无需编译,大量节约了开发时间。 如果你在 Mac 上,并且开了虚拟机然后编译 VS 的话,应该有那个恐怖的按小时计算的编译时间长度经验。Clang 虽然速度比 VC 快很多,但是每次如果 clean 一下然后编译几十上百个文件也需要若干分钟。

一些问题:

  1. 太灵活,更容易出烂代码。

  2. 调试问题与 IDE 问题。
    目前在 cocos2d-x 领域,还缺乏好用的支持 JS 的 IDE 。现在目前暂时还是用 cocos2d-html5 版本做调试(两者的接口已经高度一致化),未来会有基于 c++ 的 IDE 做的 JS 调试插件(比如在 Eclipse 上面的)。

  3. 善变的 this
    this 关键字绝对是 JS 里面的变形金刚。根据不同的上下文,经常会变成其他东西。 这个经常会和回调函数问题纠缠不清,如果再加上闭包,三合一,够你喝一壶的。

  4. 闭包
    闭包很强大,无限制传参,抓取快照。 但是闭包本身的问题也不小,首先是阅读和理解上的困难,面向对象的程序员一上来很难理解这东西,从他们的角度看闭包的代码也很丑。 还有就是效率问题,同事测了一下 SpiderMonkey 中的闭包在生成大对象时效率不太高。 目前在 cocos2d-x 前端开发中,为了防止出现问题,对于缺乏经验的程序员,尽量不要使用闭包代码。 我个人在回合制战报,生成动画里是用了一些闭包的,不过那是一次性代码。

  5. 变量生命周期不明确
    变量生命周期问题,因为不需要声明,很多时候也没有特别明显的初始化,并不能通过阅读代码明确知道,一个变量的生存周期,这是所有脚本语言和 GC 语言的特性,有些时候对调试会形成麻烦。

  6. 原型继承
    难以理解的原型继承。熟悉面向对象的人一般都对这个东西莫名其妙。

从静态语言过度到动态脚本语言,一般程序员会疑惑在几个地方,this,闭包,原型继承,以及如何灵活地使用脚本语言的动态性进行编码,我观察了一下,很多人写 JS 像静态语言,还是 c++ 风格或者 Java 风格。