我们知道javascript是通过语句来构造代码的组织结构的,这种组织结构的基本形式是“代码分块”,而代码分块带来的语法效果,是信息隐藏。
一般来说,所谓信息隐藏指的是变量或者成员的可见性问题,而这个可见性的区间,则依赖语法的称述,这被称作作用域,这是对作用域的一种通俗描述,作用域包括语法作用域和变量作用域两个部分,这两个部分是一个语言中,模块化层次的全部体现。
javascript中的语法作用域有四种,大部分被严格限制在“语句/批语句”作用域内,with就在其中。
其实如果代码可读性好的代码,with是个非常有用的语句,但是目前很多网上文章包括 犀牛书,都不推荐使用with,这是为什么。
至少我是经常用到with在一些特定的场合,需要临时而短暂的切换作用域干活,比如临时切换到一个window.a.b.c.d.obj的对象来给这个obj进行一个属性的深度复制。
如果一定要说with的问题,那么我想并不是with会带来性能上的缺陷,with语句并不可怕,它有它存在理由。
那么我们抛开性能上的思路来看这么一种情况。
在 with 语句内部通过内部变量修改数值
var person = {
man : {
name: "nick"
}
};
with(person.man ) {
name = "baby";
// 显示 baby , 正确!
alert(name);
}
// 显示 baby, 正确!
alert(person.man.name);
but
var person = {
man : {
name: "nick"
}
};
with(person.man ) {
person.man = {
name : "baby"
}
// 显示 nick , why!
alert(name);
}
// 显示 baby, 正确!
alert(person.man.name);
这里一看上去 确实 有点 绕,why? with语句的作用就是把作用域切换为操作对象,with的{} 语句块 会 进入到切换后的作用域,然后等语句块执行完在切换回原来的作用域(也有说法是这样作用域的切换带来的性能消耗?这个.......)
进入with语句块的时候,js会创建一个临时的with对象,暂且称之为withobj:withobj的parent为当前的scope chain,withobj的__proto__为with语句块的参数root.branch。
with(person.man) {
person.man = {
name: "baby"
};
// 显示 "nick", 和预想的不一样! bug!!!!!!!!!!
alert(name);
}
with语句块中将person.man修改成另外一个对象,此时withobj的__proto__还是原来的对象{name:"nick"}.于是便出现了例子二的"bug".
所以with语句并没有bug,而是一个正常的语法现象。
犀牛书里也是不推荐使用with语句但是并没有提过with会带来低效,同时也简单的说了这么两点
一是代码难优化, 同比不用with的代码低
二就是我上面说的这个问题了, with语句作用域内外对象的迷魂阵