with用于擴(kuò)展一個(gè)語(yǔ)句的作用域鏈,但一般情況下不建議使用with語(yǔ)句,因?yàn)樗赡苁且鸹煜e(cuò)誤和兼容性問(wèn)題的根源。在Vue源碼中有使用with語(yǔ)句的功能點(diǎn),因此在這里將簡(jiǎn)介其功能,以助于閱讀框架源碼。
性能的利與弊
利
with
語(yǔ)句可以在不造成性能損失的情況下,減少變量的長(zhǎng)度。其造成的附加計(jì)算量很少。使用'with'可以減少不必要的指針路徑解析運(yùn)算。但是在大部分情況下,即使不使用with,使用臨時(shí)變量來(lái)保存指針或者使用call,也能達(dá)到同樣的效果。
弊
with
語(yǔ)句使得程序在查找變量值時(shí),都是先在指定的對(duì)象中查找。所以那些本來(lái)不是這個(gè)對(duì)象的屬性的變量,查找起來(lái)將會(huì)很慢。
示例
let obj = { a: 1, b: 2, c: 3 } with(obj){ console.log(a) //1 console.log(b) //2 console.log(c) //3 }
這段代碼中,with關(guān)聯(lián)的obj對(duì)象,在with代碼塊中,每個(gè)變量都首選被認(rèn)為是一個(gè)局部變量,如果這個(gè)局部變量與obj對(duì)象的某個(gè)屬性同名,則這個(gè)局部變量會(huì)指向obj對(duì)象屬性。
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沒(méi)有a屬性。fn(obj)接收一個(gè)obj形參,是一個(gè)對(duì)象引用,并執(zhí)行了with(obj)。在with代碼塊的內(nèi)部,對(duì)a實(shí)際上是一個(gè)引用,將1賦值給了a。
當(dāng)傳遞obj2給with時(shí),with所聲明的作用域就是obj2,從這個(gè)作用域下開(kāi)始對(duì)a進(jìn)行查詢。obj2的作用域、fn的作用域和全局作用域中都沒(méi)有查找到標(biāo)識(shí)符a,因此在非嚴(yán)格模式下會(huì)自動(dòng)在全局作用域創(chuàng)建一個(gè)全局變量,而嚴(yán)格模式下則會(huì)拋出ReferenceError
錯(cuò)誤。
性能降低
如果在代碼中使用了with,那么JS引擎在編譯階段只能簡(jiǎn)單地假設(shè)關(guān)于標(biāo)識(shí)符的判斷都將無(wú)效,因?yàn)榫幾g器也不能知道傳遞給with的作用域?qū)ο蟮降资钦l(shuí)。因此JS引擎在編譯階段進(jìn)行的性能優(yōu)化都將無(wú)效。最糟糕的情況,那就是如果出現(xiàn)了with,所有的優(yōu)化都將變得無(wú)意義。最簡(jiǎn)單的做法就是不做任何優(yōu)化,那么運(yùn)行起來(lái)一定會(huì)很慢,這將是無(wú)法避免的事實(shí)。
Vue中的with
Vue 在 compile 的時(shí)候,會(huì)把 template 生成對(duì)應(yīng)的 render function,而這個(gè) render function中又正好使用了with語(yǔ)句。按照上文來(lái)說(shuō),不建議使用with語(yǔ)句,為什么在Vue中又會(huì)使用到呢?