javascript中变量的范围是什么?它们在函数内部的作用域与在函数外部的作用域相同吗?或者这有关系吗?此外,如果变量是全局定义的,那么变量存储在哪里?
当前回答
(函数foo(){console.log(foo)})();console.log(foo类型);//未定义,因为“foo”的作用域是它自己的表达式//但是,像这样(函数foo(){console.log('1:',foo)//函数foofoo=100console.log('2:',foo)//函数foo,不是100,为什么?})()
其他回答
全局声明的变量具有全局范围。在函数中声明的变量的作用域是该函数,并隐藏同名的全局变量。
(我相信真正的JavaScript程序员可以在其他答案中指出许多微妙之处。特别是我在这个页面上看到了这到底意味着什么。不过,希望这个更为介绍性的链接足以让你开始。)
JS中只有函数作用域。不阻止范围!你也可以看到什么在提升。
var global_variable = "global_variable";
var hoisting_variable = "global_hoist";
// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);
if (true) {
// The variable block will be global, on true condition.
var block = "block";
}
console.log("global_scope: - block: " + block);
function local_function() {
var local_variable = "local_variable";
console.log("local_scope: - local_variable: " + local_variable);
console.log("local_scope: - global_variable: " + global_variable);
console.log("local_scope: - block: " + block);
// The hoisting_variable is undefined at the moment.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
var hoisting_variable = "local_hoist";
// The hoisting_variable is now set as a local one.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}
local_function();
// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
在EcmaScript5中,主要有两个作用域,局部作用域和全局作用域,但在EcmaScript6中,我们主要有三个作用域:局部作用域、全局作用域和一个称为块作用域的新作用域。
块范围示例如下:-
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
最初由Brendan Eich设计的JavaScript中的作用域概念来自HyperCard脚本语言HyperTalk。
在这种语言中,显示类似于一堆索引卡。有一张主卡被称为背景。它是透明的,可以看作是底牌。此基础卡上的任何内容都与放在其上面的卡共享。放在上面的每张卡都有自己的内容,这些内容优先于前一张卡,但如果需要,仍然可以访问前一张卡片。
这正是JavaScript作用域系统的设计方式。它只是有不同的名字。JavaScript中的卡片称为Execution ContextsCMA。这些上下文中的每一个都包含三个主要部分。变量环境、词汇环境和此绑定。回到卡片参考,词汇环境包含堆栈中较低的先前卡片的所有内容。当前上下文位于堆栈的顶部,其中声明的任何内容都将存储在变量环境中。在命名冲突的情况下,变量环境将优先。
此绑定将指向包含对象。有时,作用域或执行上下文在包含对象不变的情况下发生变化,例如在声明的函数中,包含对象可能是窗口或构造函数。
这些执行上下文是在任何时候传输控制时创建的。当代码开始执行时,控制权被转移,这主要是通过函数执行完成的。
这就是技术解释。在实践中,记住在JavaScript中
范围在技术上是“执行上下文”上下文形成存储变量的环境堆栈堆栈的顶部优先(底部是全局上下文)每个函数都创建一个执行上下文(但不总是一个新的此绑定)
将此应用于前面的一个示例(5。“闭包”),可以遵循执行上下文的堆栈。在本例中,堆栈中有三个上下文。它们由外部上下文、var six调用的立即调用函数中的上下文以及var six立即调用函数内部返回函数的上下文定义。
i) 外部上下文。它的可变环境为a=1ii)IIFE上下文,它有一个a=1的词法环境,但一个a=6的变量环境在堆栈中优先iii)返回的函数上下文,它具有a=6的词法环境,这是调用时警报中引用的值。
内联处理程序
前端代码编写者经常遇到的一个尚未描述的非常常见的问题是HTML中内联事件处理程序可见的范围,例如
<button onclick="foo()"></button>
on*属性可以引用的变量范围必须是:
全局(工作内联处理程序几乎总是引用全局变量)文档的属性(例如,作为独立变量的querySelector将指向document.querySelector;罕见)处理程序附加到的元素的属性(如上所述;罕见)
否则,当调用处理程序时,将得到ReferenceError。因此,例如,如果内联处理程序引用了在window.onload或$(function){中定义的函数,则引用将失败,因为内联处理程序只能引用全局范围内的变量,而函数不是全局的:
window.addEventListener('DOMContentLoaded',()=>{函数foo(){console.log('运行');}});<button onclick=“foo()”>单击</button>
文档的财产和处理程序附加到的元素的财产也可以作为内联处理程序中的独立变量引用,因为内联处理函数是在两个块中调用的,一个用于文档,另一个用于元素。这些处理程序中变量的作用域链非常不直观,并且一个工作的事件处理程序可能需要一个函数是全局的(并且应该避免不必要的全局污染)。
由于内联处理程序内部的作用域链非常奇怪,而且内联处理程序需要全局污染才能工作,并且内联处理程序在传递参数时有时需要丑陋的字符串转义,因此可能更容易避免它们。相反,使用Javascript(如addEventListener)而不是HTML标记附加事件处理程序。
函数foo(){console.log('运行');}document.querySelector('.my button').addEventListener('click',foo);<button class=“my button”>单击</button>
模块(<script type=“module”>)
另一方面,与在顶层运行的普通<script>标记不同,ES6模块内的代码在其自己的私有范围内运行。在普通<script>标记顶部定义的变量是全局的,因此您可以在其他<script>标签中引用它,如下所示:
<脚本>const foo=“foo”;</script><脚本>console.log(foo);</script>
但是ES6模块的顶层不是全局的。在ES6模块顶部声明的变量仅在该模块内部可见,除非该变量被显式导出,或者除非它被分配给全局对象的属性。
<script type=“module”>const foo=“foo”;</script><脚本>//无法在此处访问foo,因为其他脚本是模块console.log(foo类型);</script>
ES6模块的顶层与普通<script>中顶层IIFE内部的顶层类似。模块可以引用任何全局变量,除非模块为其明确设计,否则任何内容都不能引用模块内部的任何内容。
推荐文章
- 什么时候JavaScript是同步的?
- 如何在Typescript中解析JSON字符串
- Javascript reduce()在对象
- 在angularJS中& vs @和=的区别是什么
- 错误"Uncaught SyntaxError:意外的标记与JSON.parse"
- JavaScript中的querySelector和querySelectorAll vs getElementsByClassName和getElementById
- 给一个数字加上st, nd, rd和th(序数)后缀
- 函数可以作为参数传递吗?
- 如何以编程方式触发引导模式?
- setTimeout带引号和不带括号的区别
- 在JS的Chrome CPU配置文件中,'self'和'total'之间的差异
- 用javascript检查输入字符串中是否包含数字
- 如何使用JavaScript分割逗号分隔字符串?
- 在Javascript中~~(“双波浪号”)做什么?
- 谷歌chrome扩展::console.log()从后台页面?