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) //1fn(obj2)console.log(obj2.a) //undefinedconsole.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中的with
Vue 在 compile 的时候,会把 template 生成对应的 render function,而这个 render function中又正好应用了with语句。依照上文来说,不倡议应用with语句,为什么在Vue中又会应用到呢?
function render () { with (this) { return _c('div',{on:{"click":change}},[_c('span',[_v(_s(number))]),_v(" "),_c('span', [_v(_s(name))])]) }}
因为with 的作用域和模板的作用域正好符合,能够极大地简化模板编译过程。而with的代码量很少,把作用域的解决交给JS引擎来做也更牢靠。当然,最现实的状况还是要去掉with的应用,预编译的时候会主动把第一遍编译生成的代码进行一次额定解决,用残缺的AST剖析来解决作用域,把with拿掉,顺便反对ES6语法。换句话说,如果用 webpack + vue 的时候,最终生成的代码是没有 with 的。