gpt4 book ai didi

Javascript 闭包和全局变量

转载 作者:行者123 更新时间:2023-12-03 09:10:20 25 4
gpt4 key购买 nike

我刚刚学习闭包的工作原理并开始使用一些代码。据我了解,闭包是某种内存,它在创建闭包的状态下保存函数的环境,并且即使父函数已经结束,它仍然处于事件状态(当返回或绑定(bind)到事件时)。

所以我尝试了下面的代码,它按预期工作。两个按钮将其相应的文本框从“检查”切换到“已保存”。

//var v1;
//var v2;
//var v3;

function func1(src, action, arg) {
document.getElementById(arg).value = "check";
document.getElementById(src.id).onclick = function() {
func2(src, action, arg);
};
//v1 = src;
//v2 = action;
//v3 = arg;
}

function func2(v1, v2, v3) {
document.getElementById(v3).value = "saved";
document.getElementById(v1.id).onclick = function() {
func1(v1, v2, v3);
};
}
<input type=text id="t1">
<input type=button id="btn1" value="Go 1" onclick="func1(this, 'edit', 't1')">
<input type=text id="t2">
<input type=button id="btn2" value="Go 2" onclick="func2(this, 'edit', 't2')">

但现在困惑来了。当我使用全局变量在 func2() 中构造闭包时,切换错误。请参阅下面的代码:

var v1;
var v2;
var v3;

function func1(src, action, arg) {
document.getElementById(arg).value = "check";
document.getElementById(src.id).onclick = function() {
func2();
};
v1 = src;
v2 = action;
v3 = arg;
}

function func2() {
document.getElementById(v3).value = "saved";
document.getElementById(v1.id).onclick = function() {
func1(v1, v2, v3);
};
}
<input type=text id="t1">
<input type=button id="btn1" value="Go 1" onclick="func1(this,'edit','t1')">
<input type=text id="t2">
<input type=button id="btn2" value="Go 2" onclick="func2(this,'edit','t2')">

点击 Go1 -> Textbox1 = 检查;单击 Go2 -> Textbox2 = 检查;但现在单击 Go1 -> Textbox2(而不是 1)= 已保存。

如此看来,闭包内的变量v1、v2、v3仍然使用闭包外的全局值。有人可以解释一下为什么以及该怎么做才能使其与全局变量一起使用吗?

<小时/>

感谢 T.J.Crowder,我更新了代码以在闭包中使用私有(private)变量。但不幸的是它仍然不起作用。与第二个代码块的行为相同。

var v1;
var v2;
var v3;

function func1(src, action, arg) {
document.getElementById(arg).value = "check";
document.getElementById(src.id).onclick = function() {
func2();
};
v1 = src;
v2 = action;
v3 = arg;
}

function func2() {
var private1 = v1;
var private2 = v2;
var private3 = v3;

document.getElementById(private3).value = "saved";
document.getElementById(private1.id).onclick = function() {
func1(private1, private2, private3);
};
}
<input type=text id="t1">
<input type=button id="btn1" value="Go 1" onclick="func1(this,'edit','t1')">
<input type=text id="t2">
<input type=button id="btn2" value="Go 2" onclick="func2(this,'edit','t2')">

最佳答案

So it seems that the variables v1, v2, v3 in the closure still uses the global values outside the closure

是的,因为没有什么可以遮蔽他们,所以这就是他们最终得到解决的方式。

在您的第一个代码块中,onclick 处理程序使用 srcactionarg 参数在对 func1 的调用中提供,以及在对 的调用中提供的 v1v2v3 参数>func2.

在第二个示例中,由于您删除了 func2 的参数,这些标识符位于它创建的 onclick 函数范围内的唯一原因是全局变量;如果没有全局变量,您将收到 ReferenceError,因为这些标识符将无法解析。所以使用的是全局变量。

如果您在第二个示例中将参数传递给具有相同名称的 func2 (不是一个好主意,但只是为了解释),则 onclick 使用的标识符 它创建的闭包将针对这些参数进行解析,而不是针对全局变量。

解释这一行的作用可能会很有用:

document.getElementById(v1.id).onclick = function () { func1(v1,v2,v3); };

该行创建了一个函数,它是创建它的上下文的闭包,调用 func2 (并且该上下文引用了它被创建的上下文,等等取决于全局背景)。 onclick 闭包没有创建时范围内的变量的副本,它具有对它们的持久引用。因此,当函数运行时,将使用当时变量的值。在第一个示例中,这些值永远不会改变,因为它们是在创建闭包的调用期间传递给 func2 的参数值,并且不会改变这些值。不过,在第二个示例中,这些值不同,因为您使用的是全局变量,而不是传递给 func2 的参数。

由于闭包具有对其创建位置的上下文的引用,因此对 func2每次调用的上下文均由该调用中创建的闭包保留。因此,如果保留由多个调用创建的闭包,则会保留对 func2 的调用的多个上下文,因此保留参数的多个副本(每个副本都由为该上下文创建的闭包使用)。一个更简单的例子可能会有所帮助:

// A global variable
var global = "g";

// A function that creates and returns a closure
function foo(arg) {
return function() {
snippet.log("global = " + global +) ", arg = " + arg);
};
}

// Create a closure over arg = 42
var f1 = foo(42);
f1(); // global = g, arg = 42

// Change global
global = "g+";
f1(); // global = g+, arg = 42

// Create a second closure over a second arg, 67
var f2 = foo(67);
f2(); // global = g+, arg = 67

// Change global again
global = "g++";
f1(); // global = g++, arg = 42
f2(); // global = g++, arg = 67
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

请注意每个闭包如何拥有自己的 arg 副本,但它们都共享 global

此代码片段演示了闭包拥有的是对 arg 的引用,而不是其值的副本:

function foo(arg) {
return {
showArg: function() {
console.log("arg = " + arg);
},
incrementArg: function() {
++arg;
}
};
}
var o1 = foo(42);
o1.showArg(); // arg = 42
o1.incrementArg();
o1.showArg(); // arg = 43
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

您可能会发现我贫血的小博客上的这篇文章很有用:Closures are not complicated

<小时/>

这是一个片段,演示了如何在调用 func2 的闭包中捕获当时的全局变量,但我们最终只是复制 src 中已有的内容, actionarg,所以没有意义。

var v1;
var v2;
var v3;

function func1(src, action, arg) {
var p1 = src, p2 = action, p3 = arg; // Just duplicates what we already have
document.getElementById(arg).value = "check";
document.getElementById(src.id).onclick = function() {
func2(p1, p2, p3); // We could just use src, action, and arg here like your first example
};
v1 = src;
v2 = action;
v3 = arg;
}

function func2(v1, v2, v3) {
document.getElementById(v3).value = "saved";
document.getElementById(v1.id).onclick = function() {
func1(v1, v2, v3);
};
}
<input type=text id="t1">
<input type=button id="btn1" value="Go 1" onclick="func1(this,'edit','t1')">
<input type=text id="t2">
<input type=button id="btn2" value="Go 2" onclick="func1(this,'edit','t2')">

关于Javascript 闭包和全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32091185/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com