JS自学深入了解必看!每天一个小知识:有趣的JS作用域进阶——欺骗词法作用域

简介

在了解如何欺骗之前先简单的介绍一下词法作用域吧:

js 复制代码
if(1){
  let a = 1
}
  console.log(a);

我们可以通过这样一个比较简短的代码来感受一下词法作用域,可以来猜一猜我们运行之后的结果是什么 如果你已经知道了那么说明你对它有一个不错的认识了,如果不太确定的话答案就在下面

词法作用域

词法作用域是由你的代码中将变量和块作用域写在哪里来决定的。比如上面的if,let 在{}中定义了一个变量a,那么a的词法作用域就在if的块区域之中,也就是出生在哪他的词法作用域就在哪

这就是他的词法作用域

那么上面那段代码究竟会输出什么呢? 答案是由于在全局中找不到a的声明,所以将会抛出一个报错。当然神奇的是如果你将let换成var,他将会输出1,原因就是由于变量提升事实上var的声明跳出了if,那么它的作用域就是全局。当然我们今天的主题并不是var的变量提升,接下来让我们来看看怎么"欺骗"词法作用域吧!

欺骗词法作用域

词法作用域完全由词法"出生"的位置来定义,但JavaScript中有两个机制来实现在运行时来"修改"(或者说欺骗)词法作用域。分别是eval(..)函数和with关键字

1.eval

js 复制代码
let input = function(str){
  eval(str)
  console.log(a);
}
  var a = 1
  input('var a = 3')

eval(..)函数的作用其实就可以理解为将其中的内容搬到调用这个函数的时候去用,也就是说此时运行代码你会得到3。而按照正常的理解来说内部没有找到var声明就需要向外寻找那么会找到1,而且因为词法作用域问题eval函数中的声明也不应该在上一级的input中生效可是神奇的是这个方法让a成功被声明了,说明eval函数中声明的变量的词法作用域被改变了!

2.with

而另一个做到欺骗词法作用域的就是with,with通常被用来修改对象的多个值,如下图:

js 复制代码
// 创建对象
let 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 
}

  

那么它又是怎么欺骗词法作用域的呢?我们来看这样一段代码

js 复制代码
function foo(obj){
  with(obj){
    c = 1
  }
}
let obj = {
  a : 1
}
foo(obj)
console.log(c); 

首先我们来简单的理解一下,我们利用with对一个obj中的c进行了改变,但事实上obj中并没有c的存在,那么最后我们打印c的时候应该是报错的,因为我们并没有定义一个c对吧?可是你可以尝试运行一下这段代码,你会惊奇的发现:输出了1!没错,c被输出了,可是无论怎么看c的作用域都不可能是全局的,可log在全局只能输出作用域在全局变量。那么这到底是为什么呢?

其实这被称为"泄露",with将c泄露到了全局,因为它并没有在obj中找到c,结果它就非常离谱的在全局凭空创造了一个变量c并且给它赋了值。

相比于eval只是给声明"搬了个家",with直接"建了个家"从而欺骗词法作用域更加离谱,它们二者都会拖慢代码的运行,除去一些特殊情况我们可以尽量不要使用这两种机制。

那我们今天的小知识分享就结束了,如果可以请看到这的小伙伴给作者的辛苦点个小小的赞吧~~

相关推荐
diygwcom几秒前
electron-updater实现electron全量版本更新
前端·javascript·electron
volodyan3 分钟前
electron react离线使用monaco-editor
javascript·react.js·electron
^^为欢几何^^12 分钟前
lodash中_.difference如何过滤数组
javascript·数据结构·算法
Hello-Mr.Wang17 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘44 分钟前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
北岛寒沫5 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
everyStudy5 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
无心使然云中漫步6 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者7 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_7 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js