說起編程語言,理科生們最初接觸的應當是C++。那是P校的必修課。 事實上第一個讓我認真去用的語言是.NET C#, 我學習了幾乎所有的語言特性、窗口控件以及WPF樣式字典。 這樣便可以成為一個C#偽專家,去解答別人關于C#的各種問題 :)

此后由于各種原因去學習JavaScript、Python、Ruby,逐漸地發現成功使用一門語言的關鍵不在于熟悉所有語言特性,而是學著只用那些優雅的、表達力強的語言特性來完成整個工程。

那么JavaScript能否進化為一個只包含有點的語言呢? 在這一點上標準化協會其實也無能為力,去除任何語言特性都會造成依賴于該特性的工程失效。 我們可以使用JSLint等工具來提示我們,確保項目中沒有使用那些糟糕的語言特性。

JavaScript 的詬病

JavaScript可以是天使,也可以是魔鬼!
多數語言都有自己的優勢和缺憾,JavaScript也不例外。 我們能做的就是盡量去使用那些優雅的部分,而避免使用那些復雜的、易出錯的特性。

JavaScript的成長過程并不完美。我們知道Java語言的設計經過了完整的標準化和設計流程, 堪稱是完美的面向對象編程語言。 而JavaScript被Netscape瀏覽器引入之后便迅速地被全球開發者采用, 甚至都沒有實驗室的測試期。雖然JavaScript沒有完美的成長過程, 但它仍然包含了非常多優雅的、表達力強的語言特性,這也是它能打敗Java Applet的原因之一。

JavaScript并不是非常難用的語言。瀏覽器成就了JavaScript的流行, 而DOM的糟糕也使得JavaScript廣受詬病。 DOM甚至還沒有完整的標準,不同瀏覽器實現也不一致, 這使得任何語言都很難操作DOM,這并非JavaScript的問題。 與此相反,JavaScript的神奇之處在于任何人都可以馬上上手, 不需要了解多少JavaScript語言特性,甚至不需要會編程。

JavaScript 的兩面

JavaScript的設計中包含了優秀的部分和糟糕的部分。 其中優秀的特性包括:函數、弱類型、動態對象、優雅的對象表示法; 全局變量則是最糟糕的特性之一。

函數是JavaScript的一級對象,可以被傳參、返回以及賦值。 同時JavaScript函數也是特殊的,它擁有詞法作用域,這也是閉包的原理。

弱類型。當今編程語言都比較偏向強類型,其設計思想是將錯誤的發現提前到編譯期。 尤其是C++:如果編譯通過,那么程序就應當正確運行,否則就是代碼設計有問題。 但任何強類型語言都少不了測試,那么為何不使用更輕松的弱類型語言呢? 況且強類型語言給出的編譯錯誤大多不是代碼中真正的問題所在。

Java給出的數百行調用堆棧純屬無用,除非程序員是一臺電腦。
JavaScript對象。JavaScript的對象表示法啟發了JSON數據格式, 列舉屬性的方式確實更加直觀,更加具有表達力。 JavaScript的原型繼承方式卻是一個備受爭議的特性。

全局變量應當是最糟糕的設計。JavaScript需要全局變量來完成鏈接。JavaScript鏈接時會將所有編譯單元的全局變量合并到global對象(在瀏覽器中,通常是window對象)下。

JavaScript代碼片段

下面給出一段JavaScript來感受一下JavaScript的簡潔。 這是brick.js項目中的JavaScript代碼片段,它們的用途分別是更新this.modules以及合并編譯LESS代碼。

Static.prototype.update = function(type) {
    var staticFile = type === 'css' ? 'cssPath' : 'cltPath';

    var ps = _.map(this.modules, mod =>
        file.read(mod[staticFile])
        .catch(e => false)
        .then(file => mod[type] = file || '')
    );
    return Promise.all(ps);
};

Static.prototype.getCss = function() {
    var modules = this.modules,
        comment = this.config.css.comment;
    var src = _.reduce(modules, (res, mod) =>
        res + lessForModule(mod, comment), '');
    return compileLess(src, {
        compress: this.config.css.compress
    });
};

上述代碼使用了ES6的新特性,包括Lambda表達式、內置Promise等(當然我引入了promise-helper)。 JavaScript取默認值的||操作符,數組的map, reduce等操作也非常簡潔。