前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >词法作用域

词法作用域

作者头像
Karl Du
发布2020-10-23 17:19:59
5120
发布2020-10-23 17:19:59
举报
文章被收录于专栏:Web开发之路Web开发之路

词法作用域

作用域共有两种主要的工作模式,第一种最为普遍,被大多数编语言所采用的词法作用域,另一种叫做动态作用域,仍有一些编程语言在使用(Bash脚本、Perl中的一些模式等)

大多数标准语言编译器的第一个工作阶段叫作词法化(也叫单词化),词法化的过程会对源代码中的字符进行检查。词法作用域就是定义在词法阶段的作用域,由 变量和作用域的位置 来决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况是这样)

代码语言:javascript
复制
// 三层嵌套的作用域
// 作用域气泡由其对应的作用域代码块写在哪里决定的,是逐级包含的
function foo(a) {
  var b = a * 2;
  function bar(c) {
    console.log(a, b, c);
  }
  bar(b * 3)
}
foo(2)

查找

作用域气泡的结构和互相之间的位置关系给引擎提供了足够的位置信息,引擎用这些信息来查找标识符的位置。比如bar函数里做了三个RHS查询,首先会在 bar 作用域气泡里去查找,如果没有会向上级作用域foo作用域气泡去查找,当查找到bfoo的作用域里,则会停止查找。多层嵌套作用域可以定义同名的标识符,这叫作“遮蔽效应”(内部的标识符遮蔽了外部的标识符)

全局变量

全局变量会自动成为全局对象window的属性,因此,可以不直接通过全局对象的词法名称,而是间接的通过对全局对象属性的引用来间接访问。

通过这种技术可以访问那些被同名变量所遮蔽的全局变量,但非全局的变量如果被遮蔽了,无论如何都无法被访问到了。

无论函数在哪里被调用,且无论它如何被调用,它的词法作用域都只有函数被声明所处的位置决定。

注:词法作用域只会查找一级标识符,比如a 。如果代码中引用了foo.bar.baz,作用域只会试图查找到 foo的作用域,然后通过属性访问规则,去对barbaz进行属性访问。

欺骗词法

如果说词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来“修改”词法作用域?

JavaScript提供了两种机制,一种时eval还有一种是with

社区普遍认为在代码中使用这两种机制不是什么好主意,最容易被人们忽略掉的点是:欺骗词法作用域会导致性能下降

在详细解释性能问题之前,首先先看一下这两种机制是什么原理。

例外

eval

JavaScript中的eval(…)可以接受一个字符串作为参数,并将其中的内容视为好像就在书写时就存在于这个程序中这个位置的代码。

代码语言:javascript
复制
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的词法作用域进行了修改,遮蔽了外部全局作用域中的同名变量

但是在 严格模式 中,eval()在运行时有自己的词法作用域,意味着其中的声明无法修改所在的作用域

with

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

代码语言:javascript
复制
var obj = {
  a: 1,
  b: 2,
  c: 3
}

obj.a = 2;
obj.b = 3;
obj.c = 4;

with (obj) {
  a = 2,
  b = 3,
  c = 4
}

但实际上这不仅仅是为了 方便的访问代码

代码语言:javascript
复制
function foo(obj) {
  with(obj) {
    a: 2
  }
}
var obj1 = {
  a: 3
}

var obj2 = {
  b: 3
}

foo(obj1);
console.log(obj1.a); // 2
foo(obj2);
console.log(obj2.a); // undefined
console.log(a); // 2

性能

不推荐使用witheval的原因是因为会被严格模式所影响。

其次,JavaScript引擎在编译阶段会进行数项性能优化,其中有些优化依赖于能够依据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。但,如果引擎在代码中发现evalwith,那就毫无性能可言了

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020/9/28 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 词法作用域
  • 查找
  • 全局变量
  • 欺骗词法
  • 例外
    • eval
      • with
      • 性能
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档