我们知道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语句作用域内外对象的迷魂阵

 posted on 2012-05-23 16:32 落叶满长沙 阅读(...) 评论(...) 编辑 收藏