javascript with语句
不要用with
一、with 语句的使用
with
的初衷为了避免冗余的对象调用
foo.bar.data.x = 1;
foo.bar.data.y = 2;
foo.bar.data.z = 3;
with (foo.bar.data){ // 改变块内作用域
x = 1;
y = 2;
z = 3;
}
但其实用变量替换的方法也可以轻松解决
var o = foo.bar.data;
o.x = 1;
o.y = 2;
o.z = 3;
所以with似乎本来就没有存在的必要。到了如今,会去用with的人才真的是罕见。到了strict模式里,使用with会直接报错:
(function (){
'use strict';
var o = { };
with(o){
x = 1;
}
})()
// VM132:4 Uncaught SyntaxError: Strict mode code may not include a with statement
二、with 语法中的 this 指向
with 中的 this 与with外部的this指向相同
// 全局函数
function foo(_obj){
with(_obj){
console.log(this === globalThis, this.x);
}
}
foo({ x: 1}); // true undefined
// 构造函数
function Bar(){
this.x = 'bar';
this.withFunc = function(_obj){
with(_obj){
console.log(this instanceof Bar, this.x)
}
}
}
let bar = new Bar();
bar.withFunc({ x: 1}); // true "bar"
三、为什么不要使用 with 语句
- 性能问题
- 不可预测
- 优化困难
- 严格模式不支持使用with
性能问题
做个简单的测试:对对象中的某个属性连续赋值100万次,观察使用with与不使用with的时间开销
// chrome v86.0.4240.111
var o = { x: 1 };
function useWith(){
with(o){
for(let i=0; i<100*10000; i++){
x = i;
}
}
}
function noWith(){
for(let i=0; i<100*10000; i++){
o.x = i;
}
}
console.time('useWith');
useWith();
console.timeEnd('useWith');
// useWith: 168.0419921875 ms
console.time('noWith');
noWith();
console.timeEnd('noWith');
// noWith: 2.031982421875 ms
不可预测
使用with语句后代码产生的不可预测性是废弃with的根本原因。with强行割裂了词法作用域,将对象临时性地插入到了作用域链中。这使得出现了难以捉摸的代码。
栗子1
function printInput(_input){
/** * 函数的本意是将输入的对象打印出来 */
with(_input){
console.log(_input);
}
}
printInput(“正常”) // “正常”
printInput({ output: “正常”}) // { output: “正常” }
printInput({ _input: “不正常”}) // “不正常”
但当传入的参数是带有同名
_input
属性的_input
对象时,with
强行访问了_input._input
栗子2
function func(){
with({ }){
x = '插入with引入的新对象'
}
console.log(x)
}
func(); // “插入with引入的新对象”
在
with
中引入的新变量实际上是被添加到外层的function
上的代码难以优化
由于无法进行预测,不同的调用,或者即使相同的调用也会因为运行时的变化而出现偏差,代码含义只能在运行时才能被确定,从而使得代码无法在编译阶段被优化。
优化指两方面
- 解析和运行变得缓慢,指的就是之前已经谈到的性能。
- 对于代码优化和压缩工具来说,无法确定是变量还是属性(例如刚刚的
_input
),也就不能进行重命名(因为属性无法被重命名)。
还没有评论,来说两句吧...