Javascript 匿名函数中的作用域?
我来自Actionscript的背景,并且(参加派对的时间很晚)我正在尝试学习JavaScript。我正在YouTube上浏览这段视频(很不错),看到了一些我不懂的基本内容 第5行定义了Javascript 匿名函数中的作用域?,javascript,Javascript,我来自Actionscript的背景,并且(参加派对的时间很晚)我正在尝试学习JavaScript。我正在YouTube上浏览这段视频(很不错),看到了一些我不懂的基本内容 第5行定义了var工作计数。然后在一个对象中定义并返回两个匿名函数。函数引用了workcount,但workcount不在不同的范围内吗?这类似于Objective-C中的块,其中本地VAR在块内保持可访问性。这是什么有名字吗 或如果函数“知道”先前在其作用域中定义的变量,该函数是否会知道任务2“知道”task1 我搞不懂这
var工作计数。然后在一个对象中定义并返回两个匿名函数。函数引用了workcount
,但workcount
不在不同的范围内吗?这类似于Objective-C中的块
,其中本地VAR在块内保持可访问性。这是什么有名字吗
或如果函数“知道”先前在其作用域中定义的变量,该函数是否会知道任务2
“知道”task1
我搞不懂这件事,真让我讨厌
更新:感谢所有回复。我现在明白了——虽然我以前见过“闭包”这个词,但我从来没有理解过它(它似乎不是一个很有描述性的术语。在阅读过程中,我看到了“堆栈框架”这个词,然后灯泡亮了起来:堆栈…参考框架)
输出:
task1 1
task2 2
请注意,变量和两个匿名函数包装在同一个函数中(我们称之为父函数)。因此,此变量的作用域在此父函数中可用 因此,现在这个变量充当这两个内部函数的全局变量,但范围仅限于父函数。两个内部函数共享同一个变量。。在一个函数中更改变量的值也会对另一个函数产生影响 因此,按照本文中的逻辑,假设我们一个接一个地执行task1和task2。该变量最初设置为0。然后在task1中,它将递增1。这使得变量值为1(0+1)。现在在任务2中,其值也增加了1,使其值为2(1+1)
这个范围概念在JavaScript中称为闭包。在JavaScript中称为闭包 JavaScript中闭包的作用域是词法的,这意味着闭包所属函数中包含的所有内容都可以访问其中的任何变量 基本上createWorker是一个作用域,由于任务1和任务2在createWorker内声明,因此它们可以访问createWorkers作用域中声明的所有变量
但是
createWorker
无权访问任务1和任务2内声明的任何变量。任务2不知道任务1内创建的变量,任务1和任务2知道workCount。是的,函数知道其范围内的所有内容,包括彼此
你的问题有两个部分
第二部分很容易回答:首先,作用域中的所有变量和函数都是“,”允许您在声明变量之前使用它:
x = 5;
var x;
console.log(x); // Gives 5
回到你问题的第一部分:就范围而言,我不会对它做太多的扩展,因为它是这个网站和其他网站上广泛涉及的话题
基本上,它可以归结为全局范围和局部范围。全局作用域的工作原理与您可能想象的一样,变量(或函数)在全局范围内可用:
var x = 10;
function foo() {
console.log('Global scope! ' + x);
}
局部范围基本上是一个闭包内的所有内容(这个主题远远超出了这个问题),其功能是:
function foo() {
bar(); // This will work, since foo and bar share scope
foobar(); // This will not work: foobar is only in scope within bar
}
function bar() {
function foobar() {
console.log('foobar');
};
console.log('bar');
foobar(); // This will work, since foobar is defined within bar's local scope
}
使用var
声明会使事情变得更复杂一些。ES6let
声明大大简化了这一点
顺便说一句,虽然你的函数是匿名的,但它们并不是真的,因为你正在保存对它们的引用。在功能上,以下两个示例完全等效:
// These give the exact same result
function foo() {}
var foo = function() {}
// You can use either by calling
foo();
JavaScript有一些有趣的变量范围规则。下面是一个快速概述:
x = 0; // Global, as no "var" keyword preceeds it. Btw: var is optional!
var x = 0; // This is scoped to it's parent fn. Child fn's can use it.
let x = 0; // This is similar to var, but has a special use case. (See below.)
作为额外的好处,下一行代码看起来像是一个变量声明,但事实并非如此。它定义了一个常数。这是规范的一部分,也就是ES6。给你
虽然var
和let
都可以通过其直接函数和子函数进行访问,但它们的不同之处在于:let
关键字可以允许用户从父函数和子函数内部复制同名变量!这只会让JS变得更陌生
由于workCount是在父函数createWorker
中用“var”关键字定义的,因此task1
和task2
函数可以更改其值,因为它们是子函数
查看有关&keywords如何工作的MDN规范
因此,您的一些问题的答案如下:
这段代码说明了它是如何工作的
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Closure JS</title>
<script type="text/javascript">
var createWorker = function () {
var workCount = 0;
var task1 = function () {
var t = t || 0;
workCount += 1;
console.log("task1: " + workCount);
console.log("task1 t: " + (t++));
}
var task2 = function () {
var t = t || 0;
workCount += 1;
console.log("task2: " + workCount);
console.log("task2 t: " + (t++));
}
return {
job1: task1,
job2: task2
};
}
var app = new createWorker();
</script>
</head>
<body>
<div>
<input type="button" value="task1" onclick="app.job1()" />
<input type="button" value="task2" onclick="app.job2()" />
</div>
</body>
</html>
很容易看出,task1和task2知道它们的父作用域,而对彼此以及之前的执行一无所知。球就是这样反弹的。你可以像下面那样编写代码,javascript也会这样解释
var createWorker = function(){
var workCount, task1, task2;
workCount = 0;
task1 = function(){
workCount += 1;
console.log("task1" , workCount);
};
task2 = function(){
workCount += 1;
console.log("task2" , workCount);
};
return {
job1: task1,
job2:task2
}
};
这里发生的是,变量定义在封闭函数块的顶部。不管它们是按什么顺序定义的。因此,不仅task2
知道task1
,task1
也知道task2
。然而,作业的顺序很重要。考虑代码:
函数foo1(){
console.log(“foo1:+a”);
var a=“你好”;
}
函数foo2(){
var a=“你好”;
console.log(“foo2:+a”);
}
函数foo3(){
控制台日志(“foo3:+a”);
让a=“你好”;
}
函数foo4(){
控制台日志(“foo4:+b”);
}
var b=5;
foo1();//未定义
foo2();//你好
试一试{
foo3();//抛出ReferenceError
}捕获(e){
console.log(“foo3:+e.message”);
}
foo4();
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Closure JS</title>
<script type="text/javascript">
var createWorker = function () {
var workCount = 0;
var task1 = function () {
var t = t || 0;
workCount += 1;
console.log("task1: " + workCount);
console.log("task1 t: " + (t++));
}
var task2 = function () {
var t = t || 0;
workCount += 1;
console.log("task2: " + workCount);
console.log("task2 t: " + (t++));
}
return {
job1: task1,
job2: task2
};
}
var app = new createWorker();
</script>
</head>
<body>
<div>
<input type="button" value="task1" onclick="app.job1()" />
<input type="button" value="task2" onclick="app.job2()" />
</div>
</body>
</html>
task1: 1
task1 t: 0
task1: 2
task1 t: 0
task2: 3
task2 t: 0
task2: 4
task2 t: 0
var createWorker = function(){
var workCount, task1, task2;
workCount = 0;
task1 = function(){
workCount += 1;
console.log("task1" , workCount);
};
task2 = function(){
workCount += 1;
console.log("task2" , workCount);
};
return {
job1: task1,
job2:task2
}
};