專案由Knockout.js  3.2升級到3.3後,某個網頁原本使用<!-- ko if … -->切換元素顯示的功能失效,抓了一陣子才發現原來是寫法有誤,原本該寫<!-- ko if: someFalg -->卻寫成<!-- ko if (someFlag) -->,修改為<!-- ko if: someFlag -->問題即告排除。

但這激起我的好奇心,想找出3.2到3.3造成此一行為差異的根源改變。(其實是手癢想練習JavaScript偵錯技巧)

用一段小程式重現問題:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>if/ifnot Test</title>
</head>
<body>
  <input type="checkbox" data-bind="checked: Flag" />
  Flag = <span data-bind="text: Flag"></span>
  <div>
  <!-- ko if (Flag) -->
  Flag On
  <!-- /ko -->
  <!-- ko ifnot (Flag) -->
  Flag Off
  <!-- /ko -->
  </div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
  <script>
  ko.applyBindings({ Flag: ko.observable(true) });
</script>
</body>
</html>

測試結果,使用KO 3.2可以順利切換Flag On及Flag Off,使用KO 3.3則if/ifnot失效,Flag On及Flag Off永遠出現。

開啟F12偵錯,設定中斷點,一步一步挖進去,終於找出差異禍首:

KO 3.3調整了內部函式parseObjectLiteral()的邏輯,這個函式負責分析縏結字串轉為Key/Value配對,以找出對應的繫結處理器,例如:"text: Prop"會轉成Key="text",Value="Prop",代表要使用text繫結,繫結對象是Prop。

設定程式中斷點,直接呼叫parseObjectLiteral()進行測試。程式誤寫的非典型繫結字串"if(Flag)"(正確應為"if:Flag"),使用KO 3.2的parseObjectLiteral()還是可以正確解析出Key="if", Value="Flag"。

到了KO 3.3,因parseObjectLiteral()內部有個if條件修改,"if(Flag)"已不再視為有效,會被歸為unknown。至於if:Flag在KO 3.2跟3.3都可正確解析。

成功鎖定目標,偵錯練習完畢。


Comments

Be the first to post a comment

Post a comment