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直接"建了个家"从而欺骗词法作用域更加离谱,它们二者都会拖慢代码的运行,除去一些特殊情况我们可以尽量不要使用这两种机制。

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

相关推荐
前端青山3 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
从兄4 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
清灵xmf5 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
薛一半6 小时前
PC端查看历史消息,鼠标向上滚动加载数据时页面停留在上次查看的位置
前端·javascript·vue.js
过期的H2O26 小时前
【H2O2|全栈】JS进阶知识(四)Ajax
开发语言·javascript·ajax
MarcoPage6 小时前
第十九课 Vue组件中的方法
前端·javascript·vue.js
你好龙卷风!!!7 小时前
vue3 怎么判断数据列是否包某一列名
前端·javascript·vue.js
shenweihong8 小时前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序
巧克力小猫猿9 小时前
基于ant组件库挑选框组件-封装滚动刷新的分页挑选框
前端·javascript·vue.js
嚣张农民9 小时前
一文简单看懂Promise实现原理
前端·javascript·面试