词法作用域与JavaScript的欺骗词法,前端面试前端基础

社区普遍认为使用这两种机制不是什么好主意。但我们可以来看看这两种机制的原理。

eval


eval(...) 函数接收一个字符串作为参数,并且将其中的内容当作代码(非纯字符串)来处理。(怎么有种XSS的味道了)

在执行 eval 函数后边的代码时,引擎并无感知前边的代码是以动态形式插入并对词法作用域的环境产生了修改的。引擎只会一如往常的去查找。

function foo(codeSnippet, a) {

eval(codeSnippet)

return a + b

}

var b = 2

foo(‘var b = 3’, 1) // 返回值是 4

eval函数中调用的 'var b = 3' 这段代码会被当作原本就写在那里一样来处理。

注意:在示例中为了简洁传入eval的代码片段是固定不变的,但实际情况中可以很容易的根据逻辑来修改 eval(...) 的入参。在严格模式中,eval在运行时会有其自己的词法作用域,意味着它无法修改当前所在的作用域。

function foo(codeSnippet) {

“use strict”

eval(codeSnippet)

console.log(a) // ReferenceError: a is not defined

}

foo(‘var a = 2’)

with


JavaScript另外一个现在不推荐使用的用来欺骗词法作用域的功能是 with 关键字。

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

var obj = {

a: 1,

b: 2,

c: 3,

}

// 普通的修改方式

obj.a = 2

obj.b = 3

obj.c = 4

// 使用with

with(obj) {

a = 3

b = 4

c = 5

}

但是with并不仅仅是为了方便访问对象属性,使用它时有可能会有意想不到的事情发生。

function foo(obj) {

with(obj) {

a = 1

}

}

var obj1 = {

a: 0,

}

var obj2 = {}

foo(obj1)

console.log(obj1.a) // 1

foo(obj2)

console.log(obj2.a) // undefined

console.log(a) // 1 -> 变量a泄露到了全局作用域

当对象中有with操作中相同的属性时,一切操作看起来很正常。但是当对象中没有对应名称属性可以去修改的时候却不是为此对象添加一个属性。这是为什么呢?

with本质上会把对象处理为一个完全隔离的词法作用域,所以对象的属性会被处理为定义在当前作用域中的变量。这时with关键字中的操作相当于上篇文章中提到的LHS查询,如果在当前作用域中找到该变量会进行赋值操作,找不到的话会持续向上层查找。本例中查找到全局作用域都没有发现a变量,所以引擎在全局作用域中新建了a变量并赋值为1

相比eval是接受代码片段,修改其所处的词法作用域,with则是根据传入的对象凭空创建了一个全新的作用域。

性能

虽然 eval(...)with 能帮我们实现更复杂的功能,加强代码的扩展性。但JavaScript引擎在编译阶段做的若干的性能优化都是依赖于代码词法解释时的静态分析来的。

引擎预先确定所有的所有变量和函数的定义位置,才能在执行过程中快速找到变量。如果用了eval(...)with,引擎只能假设之前关于变量位置的判断都是无效的,最悲观的情况就是如果使用它们俩,所有的优化可能都是无意义的。

所以使用它们对于程序性能的影响较大,而且不合理的使用会造成意想不到结果的产生,在使用中应该尽量避免。

小结

==

词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。

JavaScript有两个机制可以“欺骗”词法作用域:eval(...)with。他们的副作用是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎地认为这样的优化是无效的。这两个机制的使用必然会导致代码运行变慢,不要使用它们!

- EOF -

推荐阅读  点击标题可跳转

手写面试代码大全

手撕 32 个面试高频知识,轻松应对编程题

大佬日常必备的JS工具函数大全

觉得本文对你有帮助?请分享给更多人

推荐关注「前端开发博客」,提升前端技能

后台回复以下关键字:

  1. 回复「1024」领取前端进阶资料

  2. 回复「电子书」领取海量面试和JS资料

  3. 回复「资料」领取前端群分享及培训机构的资料

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
img

193)]
[外链图片转存中…(img-P7yY7Go7-1710937667194)]
[外链图片转存中…(img-3mj9IvTX-1710937667194)]
[外链图片转存中…(img-gazaO5rq-1710937667195)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-1DUSF55Y-1710937667195)]

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值