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 语句

  1. 性能问题
  2. 不可预测
  3. 优化困难
  4. 严格模式不支持使用with
  1. 性能问题

    做个简单的测试:对对象中的某个属性连续赋值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
    
  2. 不可预测

    使用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 上的

  1. 代码难以优化

    由于无法进行预测,不同的调用,或者即使相同的调用也会因为运行时的变化而出现偏差,代码含义只能在运行时才能被确定,从而使得代码无法在编译阶段被优化

    优化指两方面

    • 解析和运行变得缓慢,指的就是之前已经谈到的性能。
    • 对于代码优化和压缩工具来说,无法确定是变量还是属性(例如刚刚的 _input ),也就不能进行重命名(因为属性无法被重命名)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值