词法作用域 & 欺骗语法

词法作用域

  1. 词法作用域是定义在词法阶段的作用域,是在写代码时将变量和块作用域写在哪里来决定的。
  2. 无论函数在哪里/如何被调用,它的词法作用域都只由函数被声明时所处的位置来决定

欺骗词法

欺骗词法作用域会导致性能下降,不可使用,但是在此进行介绍其原理
1. eval:

  • eval(…)可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。换句话说,可以在你写的代码中用程序生成代码并运行,就好像代码是写在那个位置的一样。
  • 在执行eval(…)之后的代码时,引擎并不知道前面的代码是以动态形式插入进来的,并对词法作用域的环境进行修改的,引擎只会如往常的进行词法作用域查找。

观察以下代码:

function foo(str, a) {
	eval(str); // 欺骗
	console.log(a, b);// 1, 3
}
var b = 2; // 被覆盖
foo("var b = 3;", 1);

eval(…)调用中的“var b = 3;”这段代码会被当作本来就在那里一样来处理,由于这段代码声明了新的b,因此它对已经存在的foo(…)的此法作用域进行了修改,相当于在foo(…)内部创建了新变量b覆盖了外部(全局)作用域中的同名变量
当console.log被执行时,会在foo(…)的内部同时找到a和b,但是永远也无法找到外部的b,因此输出1 3,而不是2 3。
但是,在严格模式的程序中,eval(…)在运行时有自己的此法作用域,其中的声明无法修改所在的作用域。如下代码:

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

2. with
-with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。

var obj = {
	a: 1,
	b: 2,
	c: 3,
};
// 重复
obj.a = 2;
obj.b = 3;
obj.c = 4;
// 简单的快捷方式
with (obj) {
	a = 3;
	b = 4;
	c = 5;
}
  1. 性能
    eval和with会在运行时修改或创建新的作用域,以此来欺骗其他在书写时定义的词法作用域。如果引擎在代码中发现了二者,它只能简单地假设关于标识符位置的判断都是无效的,因为无法在词法分析阶段明确知道eval会接收到什么代码,这些代码会如何对作用域进行修改,也无法知道传递给with用来创建新词法作用域对象的内容到底是什么。而且,如果出现了eval和with,所有的优化可能都是无意义的,因此最简单的做法就是完全不做任何优化。如果代码中大量使用二者,运行起来会非常慢
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值