with用於擴充套件一個語句的作用域鏈,但一般情況下不建議使用with語句,因為它可能是引起混淆錯誤和相容性問題的根源。在Vue原始碼中有使用with語句的功能點,因此在這裡將簡介其功能,以助於閱讀框架原始碼。
with
語句可以在不造成效能損失的情況下,減少變數的長度。其造成的附加計算量很少。使用'with'可以減少不必要的指標路徑解析運算。但是在大部分情況下,即使不使用with,使用臨時變數來儲存指標或者使用call,也能達到同樣的效果。
with
語句使得程式在查詢變數值時,都是先在指定的物件中查詢。所以那些本來不是這個物件的屬性的變數,查詢起來將會很慢。
let obj = { a: 1, b: 2, c: 3 } with(obj){ console.log(a) //1 console.log(b) //2 console.log(c) //3 }
這段程式碼中,with關聯的obj物件,在with程式碼塊中,每個變數都首選被認為是一個區域性變數,如果這個區域性變數與obj物件的某個屬性同名,則這個區域性變數會指向obj物件屬性。
function fn(obj){ with(obj){ a = 1; } } let obj1 = { a: 2 } let obj2 = { b: 3 } fn(obj1); console.log(obj1.a) //1 fn(obj2) console.log(obj2.a) //undefined console.log(a) //1,變數a被洩漏到全域性作用域鏈上
上例中,obj1存在a屬性,obj2沒有a屬性。fn(obj)接收一個obj形參,是一個物件參照,並執行了with(obj)。在with程式碼塊的內部,對a實際上是一個參照,將1賦值給了a。
當傳遞obj2給with時,with所宣告的作用域就是obj2,從這個作用域下開始對a進行查詢。obj2的作用域、fn的作用域和全域性作用域中都沒有查詢到識別符號a,因此在非嚴格模式下會自動在全域性作用域建立一個全域性變數,而嚴格模式下則會丟擲ReferenceError
錯誤。
如果在程式碼中使用了with,那麼JS引擎在編譯階段只能簡單地假設關於識別符號的判斷都將無效,因為編譯器也不能知道傳遞給with的作用域物件到底是誰。因此JS引擎在編譯階段進行的效能優化都將無效。最糟糕的情況,那就是如果出現了with,所有的優化都將變得無意義。最簡單的做法就是不做任何優化,那麼執行起來一定會很慢,這將是無法避免的事實。
Vue 在 compile 的時候,會把 template 生成對應的 render function,而這個 render function中又正好使用了with語句。按照上文來說,不建議使用with語句,為什麼在Vue中又會使用到呢?
相關推薦:《》
function render () { with (this) { return _c('p',{on:{"click":change}},[_c('span',[_v(_s(number))]),_v(" "),_c('span', [_v(_s(name))])]) } }
因為with 的作用域和模板的作用域正好契合,可以極大地簡化模板編譯過程。而with的程式碼量很少,把作用域的處理交給JS引擎來做也更可靠。當然,最理想的情況還是要去掉with的使用,預編譯的時候會自動把第一遍編譯生成的程式碼進行一次額外處理,用完整的AST分析來處理作用域,把with拿掉,順便支援ES6語法。換句話說,如果用 webpack + vue 的時候,最終生成的程式碼是沒有 with 的。
相關推薦:
更多程式設計相關知識,請存取:!!
以上就是深入淺析With的使用的詳細內容,更多請關注TW511.COM其它相關文章!