我們知道javascript是通過語句來構造代碼的組織圖的,這種組織圖的基本形式是“代碼分塊”,而代碼分塊帶來的文法效果,是資訊隱藏。
一般來說,所謂資訊隱藏指的是變數或者成員的可見度問題,而這個可見度的區間,則依賴文法的稱述,這被稱作範圍,這是對範圍的一種通俗描述,範圍包括文法範圍和變數範圍兩個部分,這兩個部分是一個語言中,模組化層次的全部體現。
javascript中的文法範圍有四種,大部分被嚴格限制在“語句/批語句”範圍內,with就在其中。
其實如果代碼可讀性好的代碼,with是個非常有用的語句,但是目前很多網上文章包括 犀牛書,都不推薦使用with,這是為什麼。
至少我是經常用到with在一些特定的場合,需要臨時而短暫的切換範圍幹活,比如臨時切換到一個window.a.b.c.d.obj的對象來給這個obj進行一個屬性的深度複製。
如果一定要說with的問題,那麼我想並不是with會帶來效能上的缺陷,with語句並不可怕,它有它存在理由。
那麼我們拋開效能上的思路來看這麼一種情況。
在 with 語句內部通過內部變數修改數值
var person = { man : { name: "nick" }}; with(person.man ) { name = "baby"; // 顯示 baby , 正確! alert(name);}// 顯示 baby, 正確!alert(person.man.name);
but
var person = { man : { name: "nick" }}; with(person.man ) { person.man = { name : "baby" } // 顯示 nick , why! alert(name);}// 顯示 baby, 正確!alert(person.man.name);
這裡一看上去 確實 有點 繞,why? with語句的作用就是把範圍切換為操作對象,with的{} 語句塊 會 進入到切換後的範圍,然後等語句塊執行完在切換回原來的範圍(也有說法是這樣範圍的切換帶來的效能消耗?這個.......)
--------------------------------------------------------------華麗的解釋線--------------------------------------------
進入with語句塊的時候,js會建立一個臨時的with對象,暫且稱之為withobj:withobj的parent為當前的scope chain,withobj的__proto__為with語句塊的參數root.branch。
with(person.man) {
person.man = {
name: "baby"
};
// 顯示 "nick", 和預想的不一樣! bug!!!!!!!!!!
alert(name);
}
with語句塊中將person.man修改成另外一個對象,此時withobj的__proto__還是原來的對象{name:"nick"}.於是便出現了例子二的"bug".
所以with語句並沒有bug,而是一個正常的文法現象。
犀牛書裡也是不推薦使用with語句但是並沒有提過with會帶來低效,同時也簡單的說了這麼兩點
一是代碼難最佳化, 同比不用with的代碼低
二就是我上面說的這個問題了, with語句範圍內外對象的迷魂陣