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 中的 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 的。