gpt4 book ai didi

javascript - 无法理解项目13(Iffy)的有效JavaScript书

转载 作者:行者123 更新时间:2023-11-28 19:32:07 25 4
gpt4 key购买 nike

试图读一本关于有效javascript的精彩书籍(但我仍然是新手)。

在第13项中,它讨论了立即调用的函数表达式以创建局部作用域。

我不幸的是,但是我不能在下面的例子

function wrapElements(a) {
var result = [], i, n;
for ( i = 0, n = a.length; i < n; i++ ) {
result[i] = function() { return a[i]; };
}
return result;
}

var wrapped = wrapElements([10,20,30,40,50]);
var f = wrapped[0];
f(); // undefined....


我确实尝试过多次阅读该页面,但我还是不明白

特别是下面这本书的陈述。


  程序中的错误来自于这样一个事实,即程序员显然希望该函数在创建嵌套函数时存储i的值。但实际上,它包含对i的引用。由于i的值在创建每个函数后都会更改,因此内部函数最终会看到i的最终值。这是关于关闭的关键。
  闭包通过引用而不是按值存储其外部变量。


老实说,我理解我了解闭包是通过引用而不是通过值来存储信息,但是老实说,我无法将它们与以上段落相关联。
有人可以用更简单的术语向我解释一下,还是可以指向这篇文章?我找不到任何容易理解的东西。

谢谢您的时间提前!!

最佳答案

让我看看是否可以帮助您了解一点。立即调用函数表达式或(当我学习它们时就流行的术语)自执行匿名函数的概念可能很难理解,我建议您在深入研究之前对JavaScript有扎实的了解,但我可能能够以有助于您理解的方式向您解释。

所以-让我们开始检查可以通过以下两种方式之一完成的常规函数​​声明:

function someFunction (param1, param2) {
//do stuff
};


要么

var someFunction = function (param1, param2) {
//do stuff
};


并调用此函数,您将这样调用它:

someFunction("param1value", "param2value");


这很棒,并且可以按照预期工作。但是,如果您需要一个在运行时立即执行或调用的函数,又不想将对象添加到全局命名空间,该怎么办?这就是IIFE(SEAF)的真正好处。这是匿名函数的基本结构:

(function () {

})();


(function () {之后的第一组括号将参数传递到函数的范围内。第二组括号 })();用于调用函数并将参数传递给函数。将函数声明包装在括号中会使函数匿名,并允许其立即执行或调用。

让我们以一个非常基本的开始框架示例为例,并进行更详细的说明:

(function (window, undefined) {

})(window);


我记得当我第一次看到它的时候,我无法弄清楚这里发生了什么,以及要点是什么。。。这个函数接受两个要传递到函数范围内的参数,一个窗口对象和一个未定义的对象。 (function (window, undefined) {然后,当我们调用它时,我们仅传入一个窗口对象(全局窗口范围)。 })(window);为了帮助您理解,这就像编写一个函数并按以下方式执行它:

function doStuff (window, undefined) {
//do stuff here
};
doStuff(window);


那么,为什么人们不以这种方式编写代码,而不用担心这些IIFE?好的,用这种方式编写函数可能会阻塞全局作用域,这意味着现在定义了一个 doStuff()对象,该对象可用于整个项目的作用域。如果您有一个非常大的项目或框架,则通常只想将一个对象暴露给全局范围,并让其他所有对象保持匿名,这样就不会覆盖该对象,也不会被应用程序中可能包含的其他代码覆盖。

这确实是基础知识,但是为了帮助您更多地了解语法,让我为您提供一个实际的基本工作示例,只是帮助您将概念全神贯注。在此示例中,代码运行后,我们将直接将两个数字相乘,无论您将哪个数字传递给函数。然后,我们将结果输出到ID为“结果”的文本框。您可以在此处进行操作: http://jsfiddle.net/k7f4n0mk/

(function (number1, number2) {
document.getElementById("result").value = (number1 * number2);
})(5, 10);


如果我们要在没有IIFE的情况下编写此代码,则首先必须定义函数,然后调用它,它看起来像这样:

function multiply(number1, number2) {
document.getElementById("result").value = (number1 * number2);
};
multiply(5, 10);


您可以在此处看到此示例: http://jsfiddle.net/k7f4n0mk/1/

这两个示例都产生完全相同的结果,并且我假设您对第二个示例相当满意,因为它是该语言的基础知识之一,因此,如果您担心这种全新的函数编写方式,为什么还要担心呢?旧的方法行得通吗?好了,这又回到了保持全局范围清洁和保护本地范围的角度。

每个人都非常熟悉jQuery javascript库。 jQuery的整个上下文都包装在IIFE中,只有jQuery和别名$对象暴露在全局范围内-这对于jQuery所做的一切都非常令人印象深刻。好吧,如果jQuery没有这种IIFE语法,那么它们声明的每个函数将对全局作用域可用,并且很容易被不知情的用户覆盖。他们可能会覆盖jQuery使用的任何功能并完全破坏该库-因此,我们希望保护jQuery使用的所有功能(本地作用域),并仅通过暴露必要的对象(jQuery和$)来保持全局作用域清洁。

我知道这是一个很长的答案,但是我希望我能够帮助您对这个问题有更多的了解。如果您还有其他问题,请告诉我。

-编辑-

关于您的问题-让我看看是否可以帮助您详细解释。

这是您正在使用的代码:

function wrapElements(a) {
var result = [], i, n;
for (i = 0, n = a.length; i < n; i++) {
result[i] = function () { return a[i]; };
}
return result;
}

var wrapped = wrapElements([10, 20, 30, 40, 50]);
var f = wrapped[0];
f();


现在,当您致电 var wrapped = wrapElements([10, 20, 30, 40, 50]);

包装式现在引用一个函数数组,因为这就是您要在for循环中返回的内容:

wrapped = [function () { return a[i]; },function () { return a[i]; },function () { return a[i]; },function () { return a[i]; },function () { return a[i]; }]


然后,当您调用 var f = wrapped[0]时,f成为对数组中第一个函数的引用

f = function () { return a[i]; }


因此,您在这段代码中所做的就是向循环中的数组添加一个新函数。如果尝试调用该函数,则 ai将是未定义的,这就是为什么您收到未定义的错误的原因。

为了获得所需的结果,代码如下所示:

function wrapElements(a) {
var result = [], i, n;
for (i = 0, n = a.length; i < n; i++) {
result[i] = a[i];
}
return result;
}

var wrapped = wrapElements([10, 20, 30, 40, 50]);
var f = wrapped[0];


希望这对您有所帮助。如果您需要任何进一步的帮助,请告诉我。

关于javascript - 无法理解项目13(Iffy)的有效JavaScript书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26549427/

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