JavaScript 的 with 該不該用呢?

如果您從沒用過 with 可以先看看 MDN 的說明

前一陣子讀了 Secrets of JavaScript Ninjas,個人覺得是本值得念的書。作者是有名的 jQuery 作者 John Resig,所以書中有提到一些關於 jQuery 設計相關的想法,而整本書都是圍繞在 JavaScript 中重要的基礎原理,甚至有時候引用其他 JS framework library 的 code,如果想要進階 JS 功力的話勢必是要參考一下這本書。附帶一提,John Resig 的個人網站內容也很值得一看。在看這本書的前期一直有個疑問是為什麼是 Ninjas?據說 JavaScript 高手都被稱為 JavaScript Ninjas,Quora 上還曾經有一個問題是如何成為 JavaScript Ninja。但究竟為何是 Ninja 而不是 Samuri 或是 Godzilla,我至今還未參透。

在看這本書的章節目錄時,其中令人驚訝的是居然有專門一個章節在介紹 with statement?不是從小老師就有教我們不要使用 with 嗎?而且前面我們也曾經提過使用 with 有可能會降低效能,怎麼 John Resig 還建議大家使用勒?

開始使用 with 前必須先知道一下兩點小陷阱:

陷阱一 – 無法新增 property
陷阱二 – 避免存取 with scope 外的變數 (影響效能)

關於陷阱一:

var katana = {
 isSharp: true
};

with (katana) {
 cut = function() {
 isSharp = false;
 };
};

按照 JavaScript 的設計,with (katana) 之後會在 scope chains 中最前面插入 katana 作為目前最優先的 context,所以在這 scope 下去存取 isSharp 的話可以很順利的找到 katana 的 isSharp,但是並無法找到 katana 中的 cut,於是這時候就只能夠往下一層 scope chain,一直到 global context 都找不到,於是會建立一個 global 的 cut function。但一般直覺通常會認為這個寫法會在 katana 中新增一個 cut property。很多人都會犯這個錯誤,包含小弟也是 XD

關於陷阱二:
這一點已經在上面敘述中提到,由於 with 會插入一個暫時的 scope 到 scope chain 中,而這會導致存取 with scope 之外的變數的效能變差,所以使用 with 的時候要盡量避免存取 with scope 外的變數。

在書中 John Resig 提到的前兩點關於 with 的使用時機,一個是簡化 DOM 存取的程式碼,比如說要存取 body 的 style 就必須寫 document.body.style.XXX,那如果一段 code 裡面同時需要存取很多個 body 的 style,那就要一直重覆寫 document.body.style,感覺好像很笨,而且也不簡潔。所以可以寫成:

with (document.body.style) {
 backgroundColor = "rgba(0,0,0,0)";
 backgroundImage = "url(icoding.gif)";
}

但我個人覺得好像也沒有必要因為這個用 with。因為很簡單的用一個 variable 就好了不是?

var bs = document.body.style;
 bs.backgroundColor = "rgba(0,0,0,0)";
 bs.backgroundImage = "url(icoding.gif)";

或是用 jQuery 不是更好?

$("body").css({
 "background-color" : "rgba(0,0,0,0)",
 "background-image" : "url(icoding.gif)"
});

好吧,我知道只是個例子,但簡化的方式很多,我覺得實在沒必要用 with 在這個地方。

第二點關於 with 的使用一樣是簡化,書中舉的例子是使用 YUI 時,常常會有一些 API 帶有很長的 namespace,所以也可以使用 with 來簡化而避免一直重覆相同的 namespace,關於這一點,同上,還是可以用個簡單的變數來解決。似乎也是沒必要使用 with 噢。

看完了 with 這章之後,我充滿了超多疑惑,想必 jQuery 中一定用了很多 with 吧 …
於是我把 jQuery source code 打開,search with。嗯 … 一個都沒有啊?

所以說到底呢,咱還是別用吧 🙂

後記:之前小弟看的是 unedited draft 版本,據說後來正式的版本的結論已經有建議不要使用 with …

The with statement, controversial throughout its lifetime, has no future, and its
use in new code should be avoided.



Comments
  1. 回覆

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *