JavaScript 有两种机制来实现这个目的 。 社区普遍认为在代码中使用这两种机制并不是什么好主意 , 因为:欺骗词法作用域会导致性能下降 。
在了解性能问题之前 , 先来看看这两种机制分别是什么原理 。
evalJavaScript 的 eval 函数可以接收一个字符串为参数 , 并将其中的内容视为好像在书写时就存在于程序中这个位置的代码 。 换句话说 , 可以在你写的代码中用程序生成代码并运行 , 就好像是写在那个位置一样 。
根据这个原理来理解 eval , 它是如何通过代码欺骗和假装书写时代码就在那儿 , 来实现修改词法作用域环境的?
在执行 eval 之后的代码时 , 引擎并不「知道」前面的代码是以动态的形式插入进来的 , 引擎只会如往常地进行词法作用域查找 。
function foo(stra){
eval(str) //欺骗
console.log(a b)
var b = 2
foo('var b = 3'1) // 1 3
eval 调用中的 'var b = 3' , 这段代码会被当作它们本来就在那里一样处理 。 由于那段代码声明了一个新的变量 , 因此它对已经存在的 foo 的词法作用域进行了修改 。 事实上 , 和前面提到的原理一样 , 这段代码实际上在 foo 内部创建了一个变量 b , 并遮蔽了外部作用域中的同名变量 。
当 console.log 被执行的时候 , 会在 foo 的内部同时找到 a 和 b , 但是永远也无法找到外部的 b , 因此会输出 1 3 , 而不是正常情况下的 1 2 。
默认情况下 , 如果 eval 中所执行的代码包含有一个或多个声明 , 就会对 eval 所处的词法作用域进行修改 。 技术上 , 通过一些技巧可以间接调用 eval 来使其运行在全局作用域中 ,并对全局作用域进行修改 。
JavaScript 中还有一些功能效果和 eval 很相似 , setTimeout 和 setInterval 中第一个参数可以是字符串 , 字符串的内容可以被解释为一段动态生成的函数代码 。 这些功能已经过时并不被提倡 。
new Function 函数的行为也很类似 , 最后一个参数可以接受代码字符串 , 并将其转化为动态的函数 , 这种构建函数的语法比 eval 略微安全一些 , 但也要尽量避免使用 。
【数据库|「建议收藏」词法作用域】在程序中动态生成代码的使用场景非常罕见 , 因为它所带来的好处无法抵消性能上的损耗 。
withJavaScript 中另一个难以掌握的用来欺骗词法作用域的功能是 with 关键字 。 可以有很多的方法来解释 with , 在这里我选择从这个角度来解释它:它如何同被它所影响的词法作用域进行交互 。
with 通常被当作重复引用同一个对象中的的多个属性的快捷方式 , 可以不需要重复引用对象本身 。
比如:
var obj = {
a:1
b:2
c:3
// 单调乏味的重复 obj
obj.a = 2;
obj.b = 3
obj.c = 3
// 简单快捷的方式
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) // Object { a: 2
- ios15|iOS 15.5 Beta1:建议看完果粉体验反馈再升级!
- Population|支持枪械改造,VR“吃鸡”游戏「Population: One」重大更新6月发布
- VR城建游戏|九折促销,VR城建游戏「Cities:VR」Quest 2版4月28日上线
- vrmod|「半衰期:爱莉克斯」VRMOD“Levitation”即将发布
- meta|给自媒体人的10条建议
- 美团|找工作的朋友请注意,业内人士建议,尽量避免纯技术等3类工作
- 耳机|「2022年最新」非常适合通勤、上学和远程办公的9款顶级降噪耳机
- 数据库|iOS是各大安卓系统学习的榜样,就连状态栏设计都要追随iOS!
- 「六安金安」45,晴,12~22℃,东南风3级,空气质量良
- 《花亦山心之月》新活动「花开逢君·谋成」将开启