PHP 轉 Node 筆記(一. 談談兩者的差異)

dmpty發表於2017-12-12

前言

本文章連載更新,以記錄我的學習歷程和踩過的坑,比較 NodePHP 在各種情景下的差異,分享一些實用程式碼

根據我的個人情況,Laravel 使用者是最核心的面向人群,本系列的大部分程式碼都是在 Node 下去實現傳統後端語言或是框架的特性,譬如 Laravel 的 路由/控制器/中介軟體/依賴注入 等(見 Varal),以及最近準備實現的 LaravelCollectionORM

首先容我宣告下:

  • PHP 是世界上最好的語言

這並不是開玩笑,而是在我剛剛接觸 Node 時真實的感受

1. 同步與非同步

第一個差異也是最重要的一個差異,對於習慣了同步開發的程式設計師來說最影響效率的差異。 作為 PHP 出身的我剛接觸 Node 時,因為搞不懂“為什麼 Node 程式碼裡到處都是回撥”,“為什麼不能用全域性函式”糾結了大半天,而這兩個問題在搞懂了同步非同步的差異後自然就清晰了。

PHP 是同步的(當然現在也能實現非同步程式設計,如 Swoole,並且效能不比 Node 差),一般依賴 Apache 或是 Nginx 作為 Web Server,每個請求都發生在由 php-fpm 管理的獨立的 PHP 程式上,請求結束後釋放載入的資源,所以無論是全域性變數還是全域性函式,都只會對當前請求有效

對於 Node 來說,它常駐記憶體,自身就是 Web Server,所以定義全域性變數與函式自然會影響到所有的請求,尤其是同時發生的。

舉個例子: 在 Laravel 中,用全域性函式 app() 就可以獲取到 服務容器,通過它你幾乎可以得到關於請求的所有資訊。而在 express 中,app 變數必須通過回撥的引數傳遞來獲取

2. Js 資料結構

① 型別轉換

JsPHP 一樣無需宣告變數型別以及支援自動轉換,在 PHP 中,字串拼接用 .,數值相加用 +,根據運算子來決定轉換結果,清晰明瞭,但 Js 只能用 +,這導致只要因數中存在字串,最後的結果就只能是字串。

解決方案:參考 一元正號

+'123' // 123
1 + (+'123') // 124
複製程式碼

② 陣列

Js 中的陣列並不支援 鍵值對,這導致在 PHP 中用陣列能辦到的很多事在 Js 中只能使用物件,雖然 ES6 引入了 Map 資料結構,但構造方法太反人類,存取值的方式也不方便,我認為它在大多數情況下還沒有 陣列+物件 好用

另外值得一提的是我們通常用 typeof 關鍵字來獲取 Js 的資料型別,但是 陣列物件 均返回 object,所以對於陣列,一般使用 Array.isArray() 方法來判斷

3. 遍歷

因為上述的原因通常使用物件來儲存 鍵值對 資料,導致我們經常需要用到適用於物件的遍歷語法

foo...in 在每次迭代時,將不同的屬性名分配給變數。它不應該用於迭代一個陣列,因為迭代的順序是依賴於執行環境的,所以陣列遍歷不一定按次序訪問元素。它會遍歷物件的原型,所以有時需要使用 hasOwnProperty() 來過濾原型屬性

for...of 在每次迭代中,將不同屬性的值分配給變數,但它需要物件實現了 [Symbol.iterator] 方法,詳見 for...of

所以對於簡單的用於 鍵值對 的物件使用 for...in,對於 ArrayMap 等內建物件時使用 for...of 是個比較好的選擇

4. 原生輔助方法

拿陣列舉例,PHP 提供了約 80+ 個與陣列操作有關的方法,而 JS 只有約 30+ 個,這導致被 PHP 嬌生慣養的我經常會發出感嘆:“WTF,連這個函式都要自己寫?”當然這有弊也有利,如果你非常注重程式碼質量,你一定會比較這個函式的多種實現,並選擇最優的那個,這雖然會花費不少時間,但也鍛鍊了你的演算法與思考能力

5. 類與繼承

ES6 提供了類與繼承的語言級實現,但相比 PHP 的類還有以下差別:

  • 不支援介面
  • 不支援私有方法,解決方案: 將私有方法移出類,通過 call 方法來呼叫
    class Foo {
        foo(baz) {
            bar.call(this, baz);
        }
    }
    function bar(baz) {
        return this.bar = baz;
    }
    let a = new Foo();
    a.foo(1);
    console.log(a.bar); // 1
    複製程式碼
  • 不支援私有屬性,目前已有提案,將支援私有屬性與私有方法
  • 不支援靜態屬性,解決方案:
    class Foo {
        //
    }
    Foo.bar = 1;
    console.log(Foo.bar); // 1
    複製程式碼

儘管如此,還是能用的,另外 ES6 也提供了 ProxyReflect 物件,用於攔截與定義基本操作的預設行為,等同於在語言層面做出修改,類似於 PHP 的魔法方法但是更加強大!通過它們可以為原生語言新增一些更加合理的特性

6. 生態環境

PHPComposerJsnpm,當前的趨勢,自然是後者更加火爆,說下我的感受吧:

  • 不同與 Composer 所有者/包名 的命名方式,npm 只有包名且唯一,自然有一些“佔著茅坑不拉屎”的包
  • 基數多質量自然下降,找到一個靠譜的包花費更多時間,主觀上給我一種非常亂的感覺
  • 不能完全理解一個簡單的功能甚至是一個函式也能作為一個包並且被依賴數還那麼高
  • 不能理解 express 這種輕量級框架安裝後依賴資料夾比 Laravel 還大

結語與預告

總的來說,轉換開發語言肯定是會有一點不習慣的,現在已經心平氣和的在做 Node 的開發,只是想把我當時的真實感受記錄下來,言語上多少帶點戾氣,還請前端童鞋見諒。

下一篇將會介紹我使用 Node 開發 Web Server 的歷程,感謝各位大佬的閱讀,文中錯誤歡迎指出,歡迎交流

相關文章