当前位置:网站首页>什么,你告诉我?作用域也分种类?
什么,你告诉我?作用域也分种类?
2022-08-04 14:31:00 【默海笑】
思维导图

作用域分类
静态作用域(核心:写在哪儿)
不同的编程语言采用的作用域种类也不同。js使用的是静态作用域也就是词法作用域。另外一种叫作动态作用域,仍有一些编程语言在使用(比如 Bash 脚本、Perl 中的一些模式等)。
动态作用域(核心:在哪执行)
动态作用域在运行时被动态确定的,而不是在写代码时进行静态确定的形式。
function foo() {
console.log(a); // 静态:2 动态:3
}
function bar() {
var a = 3;
foo();
}
var a = 2;
bar();
静态作用域中:foo函数就会找定义foo函数的作用域,去找到a = 2。
动态作用域中:foo函数就会找执行foo函数的作用域,去找到a = 3。
词法阶段
词法作用域的定义
词法作用域就是定义在词法阶段的作用域。就是源代码写在哪个位置来决定的,一旦写下就作用域就确定了(除了欺骗词法)。
作用域气泡
类似套娃的玩具,这里借用《你不知道的js》的图。

包含着整个全局作用域,其中只有一个标识符:foo。 包含着 foo 所创建的作用域,其中有三个标识符:a、bar 和 b。 包含着 bar 所创建的作用域,其中只有一个标识符:c。
查找
遮蔽效应
也就是就近原则,在最内侧的作用域里就能找到变量,就不会去找外侧作用域的同名变量,换句话就是,内侧作用域变量会覆盖外侧作用域同名变量。
全局变量
全局变量会自动成为全局对象(比如浏览器中的 window 对象)的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问
var num = 0
function foo() {
var num = 1;
console.log(num); // 1
function fxx() {
let num = 2;
console.log(num); // 2
console.log(window.num); // 0
}
fxx();
}
foo();
一级表示符
词法作用域查找只会查找一级标识符,比如 a、b 和 c。如果代码中引用了 foo.bar.baz, 词法作用域查找只会试图查找 foo 标识符,找到这个变量后,对象属性访问规则会分别接 管对 bar 和 baz 属性的访问。
欺骗词法
欺骗词法作用域的方法会在词法分析器处理过后依然可以修改作用域
eval
修改作用域
书写一段字符串作为eval函数的参数,就可以当做在最初就写在源代码位置了的“钉子户”。也就是以动态插入代码块到源代码的任意位置,达到修改早已决定了的作用域。
function foo(str, a) {
eval(str); // 欺骗!
console.log(a, b);
}
var b = 2;
foo("var b = 3;", 1); // 1, 3
引擎会认为最初我们书写的代码是这样的
function foo(a) {
var b = 3;
console.log(a, b);
}
var b = 2;
foo(1); // 1, 3
无论何种情况,eval(..) 都可以在运行期修改书写期的词法作用域。
严格模式
注意: 在严格模式的程序中,eval(..) 在运行时有其自己的词法作用域,意味着其 中的声明无法修改所在的作用域。
function foo(str) {
"use strict";
eval(str);
console.log(a); // ReferenceError: a is not defined
}
foo("var a = 2");
setTimeout,setInterval,new Function
setTimeout(..) 和 setInterval(..) 的第一个参数可以是字符串,字符串的内容可以被解释为一段动态生成的 函数代码。这些功能已经过时且并不被提倡。不要使用它们!(《你不知道的js》)
new Function(..) 函数的行为也很类似,最后一个参数可以接受代码字符串,并将其转 化为动态生成的函数
with
创建新的作用域
with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
function foo(obj) {
with (obj) {
a = 2;
}
}
var o1 = {
a: 3,
};
var o2 = {
b: 3,
};
foo(o1);
console.log(o1.a); // 2
foo(o2);
console.log(o2.a); // undefined
console.log(a); // 2——不好,a 被泄漏到全局作用域上了!
with 块可以将一个对象处理为词法作用域,但是这个块内部正常的 var 声明并不会被限制在这个块的作用域中,而是被添加到 with 所处的函数作用域中。
注意: 严格模式下with是禁用的。
性能
修改作用域会造成:
1、 编译时的优化会失效
2、对标识符位置判断失败
小结:
欺骗词法作用域的方法会在词法分析器处理过后依然可以修改作用域。但是js就是在编译时js引擎进行优化,一旦改变了作用域那么这些优化大多也毁于一旦。
参考
《你不知道的js(上卷)》
边栏推荐
- MySQL【窗口函数】【共用表表达式】
- CloudCompare&PCL 点云按网格划分(点云分幅)
- B. Construct a simple sequence (greedy)
- ACL 2022 | 社会科学理论驱动的言论建模
- leetcode:255 验证前序遍历序列二叉搜索树
- 关于redis的几件小事(五)redis保证高并发以及高可用
- OAID是什么
- 2042. 检查句子中的数字是否递增-力扣双百代码-设置前置数据
- Theory 1: Deep Learning - Detailed Explanation of the LetNet Model
- Sum of four squares, laser bombs
猜你喜欢
随机推荐
【问题解决】QT更新组件出现 “要继续此操作,至少需要一个有效且已启用的储存库”
第十六章 源代码文件 REST API 教程(一)
在腾讯,我的试用期总结!
如何确定异步 I/O 瓶颈
SQL语句的写法:Update、Case、 Select 一起的用法
Android Sqlite3基本命令
自监督学习未来是掩码自编码器?KAIST最新《自监督学习掩码自编码器》研究进展
CF1527D MEX Tree(mex&树&容斥)
Qt的QItemDelegate使用
metaRTC5.0新版本支持mbedtls(PolarSSL)
浙江大学团队使用基于知识图谱的新方法,从空间分辨转录组数据中推断细胞间通信状况
Bluetooth Technology|In the first half of the year, 1.3 million charging piles were added nationwide, and Bluetooth charging piles will become the mainstream of the market
OAID是什么
How to write SQL statements: the usage of Update, Case, and Select together
【HMS core】【Media】【视频编辑服务】 在线素材无法展示,一直Loading状态或是网络异常
leetcode:255 验证前序遍历序列二叉搜索树
X射线掠入射聚焦反射镜
word2003按空格键为什么会出现小数点
xampp安装包含的组件有(php,perl,apche,mysql)
期货开户之前要谈好最低手续费和交返









