- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
javascript中变量的范围是什么?它们在函数内部和外部的作用域是否相同?还是有关系吗?另外,如果变量是全局定义的,则将变量存储在哪里?
最佳答案
TLDR
JavaScript具有词汇(也称为静态)作用域和闭包。这意味着您可以通过查看源代码来确定标识符的范围。
四个范围是:
全球-一切可见
功能-在功能(及其子功能和块)中可见
块-在块(及其子块)中可见
模块-在模块内可见
在全局范围和模块范围的特殊情况之外,使用var
(函数范围),let
(块范围)和const
(块范围)声明变量。标识符声明的大多数其他形式在严格模式下具有块作用域。
总览
范围是代码库中标识符有效的区域。
词汇环境是标识符名称和与其关联的值之间的映射。
范围由词汇环境的链接嵌套组成,嵌套中的每个级别对应于祖先执行上下文的词汇环境。
这些链接的词汇环境形成范围“链”。标识符解析是沿着此链搜索匹配标识符的过程。
标识符解析仅在一个方向上发生:向外。这样,外部词汇环境无法“看到”内部词汇环境。
确定JavaScript中scope的identifier的三个相关因素:
标识符如何声明
声明标识符的地方
无论您处于strict mode还是non-strict mode
可以声明标识符的一些方式:var
,let
和const
功能参数
捕获块参数
函数声明
命名函数表达式
隐式变量声明import
语句eval
可以声明一些位置标识符:
全球背景
功能体
普通块
控制结构的顶部(例如循环,if,while等)
控制结构体
模组
声明样式
变种
使用var
声明的标识符具有函数作用域,除了直接在全局上下文中声明时,在这种情况下,它们作为属性添加到全局对象上并具有全局作用域。在eval
函数中有单独的使用规则。
let和const
使用let
和const
声明的标识符具有块范围,除了直接在全局上下文中声明时(在这种情况下,它们具有全局范围)。
注意:let
,const
和var
are all hoisted。这意味着它们的逻辑定义位置是其包围范围(模块或功能)的顶部。但是,在控制已通过源代码中的声明点之前,无法读取或分配使用let
和const
声明的变量。过渡期称为时间盲区。
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
eval
字符串中,使用
var
声明的变量将放置在当前作用域中,或者,如果间接使用
eval
,则将其用作全局对象的属性。
x
,
y
和
z
在函数
f
之外没有任何意义。
function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
y
和
z
引发ReferenceError,但不会为
x
引发ReferenceError,因为
x
的可见性不受该块的约束。定义诸如
if
,
for
和
while
之类的控制结构主体的块的行为类似。
{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope
x
具有函数作用域,因此
var
在循环外部可见。
for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)
var
声明的变量。这里仅声明变量
x
的一个实例,并且在逻辑上位于循环之外。
5
五次,然后在循环外为
5
第六次打印
console.log
:
for(var x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop
undefined
,因为
x
是块作用域的。回调是异步进行的。
let
变量的新行为意味着每个匿名函数都关闭了一个名为
x
的变量(与
var
不同),因此将打印从
0
到
4
的整数。
for(let x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined
ReferenceError
,因为
x
的可见性不受该块的限制。但是,它将打印
undefined
,因为尚未初始化变量(由于
if
语句)。
if(false) {
var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised
for
在
let
循环顶部声明的变量的作用域为循环的主体:
for(let x = 0; x < 10; ++x) {}
console.log(typeof x) // undefined, because `x` is block-scoped
ReferenceError
,因为
x
的可见性受该块的限制:
if(false) {
let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped
var
,
let
或
const
声明的变量都作用于模块:
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
var
声明的变量将作为属性添加到全局对象:
var x = 1
console.log(window.hasOwnProperty('x')) // true
let
和
const
不会向全局对象添加属性,但仍具有全局作用域:
let x = 1
console.log(window.hasOwnProperty('x')) // false
function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function
try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block
(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression
x = 1 // implicit variable declaration (no "var"!)
console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true
'use strict'
{
function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped
[[Environment]]
引用,该引用是对在其中创建它的
lexical environment(堆栈框架)的
execution context的引用。
[[Call]]
方法。此方法创建一个新的执行上下文,并在新的执行上下文和功能对象的词法环境之间建立链接。通过将功能对象上的
[[Environment]]
值复制到新执行上下文的词法环境的
outer reference字段中,可以完成此操作。
关于javascript - JavaScript中变量的范围是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38542969/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!