iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 27
6
Modern Web

重新認識 JavaScript系列 第 27

重新認識 JavaScript: Day 27 從 Page 到 Application,談談前端框架與工具庫 (上)

  • 分享至 

  • xImage
  •  

本系列文章已重新編修,並在加入部分 ES6 新篇章後集結成書,有興趣的朋友可至天瓏書局選購,感謝大家支持。

購書連結 https://www.tenlong.com.tw/products/9789864344130

讓我們再次重新認識 JavaScript!


鐵人賽寫到今天也有二十幾篇了,相信一路跟著系列文看到這裡的你,對 JavaScript 這門語言應該也有一定程度的認識了吧? 那麼在系列文的最後幾篇,就按照我最初的計畫,來與各位聊聊「JavaScript 的現在與未來: ES20XX、前端框架與開發生態圈」。

前端領域是變得簡單還是越來越難?

「每 18 至 24 個月,前端都會難一倍」

每次提及前端框架的時候,我總喜歡拿這個當開場白。當然也有人持相反意見,我覺得兩者說法其實是一體兩面,並不衝突。

是變得簡單還是越來越難,我認爲要看對於技術的掌握度以及專案的規模來決定。

如果只能用一句話來解釋,我會說前端框架/工具庫的發展方向,實際上是「讓簡單的專案變得複雜,讓複雜專案的開發變得單純」。


為什麼需要前端框架/工具庫?

在我們探討前端工具的演進之前,應該要先理解一個問題:「為什麼我們需要這些前端框架/工具庫」?

讓我們把時空背景拉回到十幾年前,那個還沒有 JavaScript 工具庫的年代。

在那個時期,各家瀏覽器對 JavaScript 的各種實作可以說是五花八門,其中最典型的例子就是「事件處理」。

在早期的 IE (也沒有那麼早,指 IE9 以前),事件綁定就分為 W3C DOM 標準的 addEventListener() 以及 IE 獨有的 attachEvent()

如果不依賴工具庫,光是要處理事件就要先做判斷:

function addEvent(ev, elem, func) {
  if (elem.addEventListener){
    // W3C DOM
    elem.addEventListener(ev, func, false);
  }
  else if (elem.attachEvent) {
    // IE DOM
    elem.attachEvent("on" + ev, func);
  }
  else {
    // No much to do
    elem[ev] = func;
  }
}

更不用說一個要加 on,另一個不用,如果同個事件綁定多個處理器,甚至連執行先後順序也不一樣。

而透過 jQuery 處理事件只需要一個 $(...).bind()$(...).on() 就足夠。

除了解決跨瀏覽器的問題之外,另一個痛點就是對於 DOM 的控制。

假設今天想要用 Javascript 讀取網頁中某個單選按鈕 (radio button),在沒有 document.querySelector 可以用的時代,來看看要怎麼做:

var checkedValue = null;
var elements = document.getElementsByTagName('input');

for (var n = 0; n < elements.length; n++){
  if (elements[n].type === "radio" &&
      elements[n].name == "radioField" &&
      elements[n].checked){
    checkedValue = elements[n].value;
  }
}

像這樣,我們必須先找出所有的 <input> 標籤,然後透過 for 一個一個檢查它的 type 以及 name,最後才把對應的 value 取出。

要是透過 jQuery 來查找,我們甚至只需要一行:

var checkValue = $('[name="radioField"]:checked').val();

就可以做到一樣的效果。

當然這篇文章並不是要教各位怎麼使用 jQuery,而是想要表達一個觀念:「框架、工具都是因應某個需要被解決的問題而生」。

而在不同的時間點,就會有不同的問題需要被解決。


前端框架/工具庫的分類

大致上來說,我會將前端框架/工具庫分做這幾種:

  • 以操作 DOM 為主:

    像大家都很熟悉的 jQuery、 YUI (我們懷念它)、或是早期的 PrototypeJS (不是 JavaScript 原生的那個 prototype)、Dojo 等都屬於這一類型。

    最近幾年才進入前端領域的朋友,可能很難想像當年 jQuery 提出可以讓開發者直接以 CSS Selector 來操作 DOM 的做法,可以說是潮到出水,簡直是屌翻天。當然 jQuery 會紅到現在其實也不只這點,還有各種其他因素就是。

    此類工具主打的就是對 DOM 的操作變得更簡便。 優點就是上手容易,操作直覺,我拿到 DOM 之後就直接對它做事。 早期大約十幾年前的主流工具庫多屬於這種類型。

  • 整合 Web UI 、處理圖形化介面為主:

    這類的工具庫通常屬於是對前一個「以操作 DOM 為主」的再擴充。

    主要想解決的目標的是把包裝好的各種圖形化介面直接拿來使用。
    像 Bootstrap、jQuery UI、Kendo UI 等這種已經幫你把幾個常用的圖形化介面都封裝好,開發者只需要準備好容器的節點,幾乎只要一初始化就可以直接使用。

    當然這種工具也是兩面刃,優點是裝了就可以直接用,但是如果要高度客製化、擴充跟改寫,如果函式庫本身沒有提供相關 api 給開發者,那麼改起來恐怕比自己刻還累。

  • 網頁模版引擎:

    像知名的 mustache.js 、node 的 jade (pug) 等都屬於這種類型。

    此類工具想要解決的問題在於將 JavaScript (程式邏輯) 與 HTML (介面) 拆分得更乾淨。

    舉例來說,今天我們從後端 api 取得某個 JSON:

    {
      "header": "Colors",
      "items": [
          {"name": "red", "first": true, "url": "#Red"},
          {"name": "green", "link": true, "url": "#Green"},
          {"name": "blue", "link": true, "url": "#Blue"}
      ],
      "empty": false
    }
    

    如果我們希望可以渲染出這樣的 HTML:

    <h1>Colors</h1>
    <li><strong>red</strong></li>
    <li><a href="#Green">green</a></li>
    <li><a href="#Blue">blue</a></li>
    

    按照傳統做法我們就得自己寫迴圈,去拼裝 HTML 對吧?
    就算用 jQuery 也要寫成這樣:

    $.get('...', function(data){
      var htmlStr = [];
      htmlStr.push(['<h1>'+ data.header +'</h1>']);
    
      for( var i = 0; i < data.items.length; i++ ){
        if( data.items[i].first ){
          htmlStr.push(['<li><strong>'+ data.items[i].name +'</strong></li>']);
        }
        else{
          htmlStr.push(['<li><a href="'data.items[i].url'">'+ data.items[i].name +'</a></li>']);
        }
      }
    
      $(...).append( htmlStr.join('') );
    })
    

    但 Mustache 可以讓你自訂網頁模版:

    <h1>{{header}}</h1>
    {{#bug}}
    {{/bug}}
    
    {{#items}}
      {{#first}}
        <li><strong>{{name}}</strong></li>
      {{/first}}
      {{#link}}
        <li><a href="{{url}}">{{name}}</a></li>
      {{/link}}
    {{/items}}
    
    {{#empty}}
      <p>The list is empty.</p>
    {{/empty}}
    

    我們只要把資料 (JSON) 準備好,然後送進模板,就會生成對應的 HTML。 就整體架構面來說,這樣拆分的結果更方便我們透過 JavaScript 來建構較具規模的應用程式,同時專案的可讀性與可維護性也大大增強。

  • 前端應用架構整合:

    現在我們把時間軸稍微往後推一些,時間來到了 2010 年前後。 由於過去不少前輩的努力,這個時候的 JavaScript 早就已經不是那個只能拿來寫寫特效啊,跑馬燈,或是簡單驗證的東西了。

    此時開發者們發現,當網站的應用程式越來越複雜的時候,即使我們已經把 HTML、CSS 以及 JavaScrpipt 都拆開維護了,在大型系統的開發架構上仍然還是覺得少了些什麼。

    於是在這個時期,各種從其他語言借鑒的特性大量被實作,MVC、MVP、MVVM ...等等框架在前端的領域可以說是蓬勃發展。

    比較早期像是 Backbone.js,算是我第一個接觸的前端 MVC 框架。 它搭配了 Underscore.js 及 jQuery,開發者可以透過 RESTful interface 來跟它的 Model 及 Collection 結合操作,當資料被改變了之後,就會觸發 View 去更新,作出對應的變化,比較可惜的是當時還沒有實作 data-binding 的部分。

    真正集大成可以算是 EmberJS、AngularJS (v1) 以及 Knockout.js 時期,這幾套前端框架各有所長,但最驚豔的部分是 View 和 Model 可以直接來做 binding,這在過去很習慣直接以操作 DOM 為開發手段的我們,其實是個相當大的突破。 除此之外,像是 directive、template 以及 routing 的整合,也為開發者帶來相當大的便利。

    然而這類「大而全」的工具在當時的時空背景下,還要顧慮到對舊環境的支援,所帶來的代價就是效能問題。

    於是,後來的故事相信大家都知道了,React 的崛起,Angular2 捲土重來,然後是 Vue 的三分天下。

    像這種類型的前端工具,都算是目前的主流框架種類。

  • 其他:

    除了前面介紹的框架/工具,另外也還有其他針對特殊目的所開發的:

    • 單元測試:
      像 Jasmine、Mocha、QUnit 等就是專門作為測試使用的工具。

    • 處理視覺化為主 (主要是處理 SVG 或 Canvas):
      比較知名的像是 D3.js、p5.js 以及 Highcharts 都是專門用來處理資料圖表使用。
      webGL 系則有老牌的 Three.js,最近超火熱的 PIXI.js 也都屬於此類的工具。

    • 純工具庫:
      單純用來作為提供 JavaScript 的增強工具庫,像是 Underscore、Lodash 等。


我並不打算在這裡一一比較各個框架,但是我們把鏡頭拉遠從過去的軌跡來看技術的發展,其實不難發現所謂後來的新技術,都是站在前人的肩膀上繼續向前走。 如同我一開始所說,框架、工具都是因應問題而生。 當新的標準、新的技術出現之後,過去曾經的問題被解決了,未來一定也會有新的挑戰等著我們去面對。

扣掉這篇距離鐵人完賽還有三天可以寫,就讓我留點篇幅在後面介紹吧 XD (打開 PS4 外出取材中)


上一篇
重新認識 JavaScript: Day 26 同步與非同步
下一篇
重新認識 JavaScript: Day 28 從 Page 到 Application,談談前端框架與工具庫 (中)
系列文
重新認識 JavaScript37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0

我要留言

立即登入留言