2014年10月16日 星期四

[JavaScript] with的用法

with這個東西平常很少見,想說上網查查時卻發現很多不同的說法。有人說少用,有人說很方便,那到底要用還是不要用呢?

來源:http://www.icoding.co/2013/02/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前必須先知道一下兩個小陷阱:

  1. 無法新增property
  2. 避免存取with csope外的變數(影響效能)
關於陷阱一:
var katana = {
 isSharp: true
};
 
with (katana) {
 cut = function() {
 isSharp = false;
 };
};
按照JavaScript的設計,with(katana)之後會在scope chains中最前面插入katana作為最優先的context,所以在這scope下去存取isSharp的話可以很順利的找到katana的isSharp,一直到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…

沒有留言:

張貼留言