又见 with

起因:


Nicholas C. Zakas 又一次抨击了邪恶的 with,并将以前的在压缩代码中带来的弊端 总结了起来。


但是如果你想详细了解下怎么回事,查查权威的OReilly.JavaScript.The.Definitive.Guide 也只能这样:


"This behavior, and the reasons behind it, are too complicated to explain here. "



规范:


这次仔细看了下规范的相关with部分,希望能够解释清楚:


1.首先是环境记录(就是常说的作用域吧)相关的条目:


10.2.1 Environment Records
Declarative environment : FunctionDeclarations, VariableDeclarations, and Catch
WithStatement:Object environment


函数,变量声明,catch都在execution context的LexicalEnvironment增加了一个声明环境记录,而with语句则增加了一个对象环境记录,对象环境记录和声明环境记录还是不一样的。


2.变量声明:

 

//1
(function () {
    var obj = {};
    with(obj) {
        var x = 1;
    }
    alert(typeof x);
    alert(typeof obj.x);
})();
alert(typeof x);

 

 

//2
(function () {
    var obj = {x:2};
    with(obj) {
        var x = 1;
    }
    alert(typeof x);
    alert(typeof obj.x);
})();
alert(typeof x);
 


12.2 VariableStatements

If a VariableDeclaration is nested within a with statement and the Identifier in the VariableDeclaration is the same as a property name of the binding object of the with statement’s object environment record, then step 4 will assign value to the property instead of to the VariableEnvironment binding of the Identifier.

10.5 Declaration Binding Instantiation


声明变量在声明环境下会执行10.5的常规操作,在当前的环境记录中绑定变量。而嵌套在with中(处于对象环境)时,则会特殊判断:如果绑定变量和对象属性名相同则直接设置对象属性值(代码行2),否则执行10.5,绑定在上一层的声明环境下(代码1)。



3.变量赋值

 

 

//1
(function () {
    var obj = {};
    with(obj) {
        x = 1;
    }
    alert(typeof x);
    alert(typeof obj.x);
})();
alert(typeof x);

 

 

 

//2
(function () {
    var obj = {x:2};
    with(obj) {
        x = 1;
    }
    alert(typeof x);
    alert(typeof obj.x);
})();
alert(typeof x);

 

 


11.13.1 simple assignment(=)


8.7.2 putValue[V,W]

If IsUnresolvableReference(V), then
a.If IsStrictReference(V) is true, then Throw ReferenceError exception.
b.Call the [[Put]] internal method of the global object, passing GetReferencedName(V) for the property name, W for the value, and false for the Throw flag.


关联环境记录中变量的查找,如果能够在最近的对象环境记录中找到相同的对象属性名则赋值对象属性(代码行2),否则沿着环境记录向上查找,找到对应环境记录的变量绑定并赋值,若最终找不到(strict现在统一false),则在全局对象中(global object)绑定变量,这正是我们应该避免的(代码行1)。



结语:


理解了上述三条,则相信对于理解 Nicholas C. Zakas说明的  为什么压缩代码不能对于with所在的作用域链的所有变量都不能简短命名的说法 能够有所帮助。

 

ps:其实 TBCompressor 比原始的 YUI Compressor好用!

 

ps2: 关于 eval

 

Ps3: NCZ javascript-minification-part-II

 

 

 

 

你可能感兴趣的:(JavaScript,C++,c,C#,yui)