前端JavaScript基础训练系列八:with关键字

在这个例子中,为了展示的方便和简洁,我们传递进去的“代码”字符串是 固定不变的。而在实际情况中,可以非常容易地根据程序逻辑动态地将字符 拼接在一起之后再传递进去。eval(…) 通常被用来执行动态创建的代码,因 为像例子中这样动态地执行一段固定字符所组成的代码,并没有比直接将代 码写在那里更有好处。
默认情况下,如果 eval(…) 中所执行的代码包含有一个或多个声明(无论是变量还是函 数),就会对 eval(…) 所处的词法作用域进行修改。技术上,通过一些技巧(已经超出我 们的讨论范围)可以间接调用 eval(…) 来使其运行在全局作用域中,并对全局作用域进行 修改。但无论何种情况,eval(…) 都可以在运行期修改书写期的词法作用域。
在严格模式的程序中,eval(…) 在运行时有其自己的词法作用域,意味着其 中的声明无法修改所在的作用域。

function foo(str) { "use strict";
eval( str );
console.log( a ); // ReferenceError: a is not defined }
                  foo( "var a = 2" );

JavaScript中 还 有 其 他 一 些 功 能 效 果 和eval(…)很 相 似。setTimeout(…)和 setInterval(…) 的第一个参数可以是字符串,字符串的内容可以被解释为一段动态生成的 函数代码。这些功能已经过时且并不被提倡。不要使用它们!
new Function(…) 函数的行为也很类似,最后一个参数可以接受代码字符串,并将其转 化为动态生成的函数(前面的参数是这个新生成的函数的形参)。这种构建函数的语法比 eval(…) 略微安全一些,但也要尽量避免使用。
在程序中动态生成代码的使用场景非常罕见,因为它所带来的好处无法抵消性能上的损 失。

with

JavaScript 中另一个难以掌握(并且现在也不推荐使用)的用来欺骗词法作用域的功能是 with 关键字。可以有很多方法来解释 with,在这里我选择从这个角度来解释它:它如何同 被它所影响的词法作用域进行交互。
with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象 本身。

比如:

var obj = { a: 1,
b: 2,
c: 3 };
// 单调乏味的重复 "obj" obj.a = 2;
obj.b = 3;
obj.c = 4;
// 简单的快捷方式 with (obj) {
         a = 3;
         b = 4;
         c = 5;
}

但实际上这不仅仅是为了方便地访问对象属性。考虑如下代码:

function foo(obj) { with (obj) {
a = 2; }
}
var o1 = { a: 3
};
var o2 = { b: 3
};
     foo( o1 );
     console.log( o1.a ); // 2
foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2——不好,a 被泄漏到全局作用域上了!

这个例子中创建了 o1 和 o2 两个对象。其中一个具有 a 属性,另外一个没有。foo(…) 函 数接受一个obj参数,该参数是一个对象引用,并对这个对象引用执行了with(obj) {…}。 在 with 块内部,我们写的代码看起来只是对变量 a 进行简单的词法引用,实际上就是一个 LHS 引用(查看第 1 章),并将 2 赋值给它。
当我们将 o1 传递进去,a=2 赋值操作找到了 o1.a 并将 2 赋值给它,这在后面的 console. log(o1.a) 中可以体现。而当 o2 传递进去,o2 并没有 a 属性,因此不会创建这个属性, o2.a 保持 undefined。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值