闭包的示例_用示例解释JavaScript中的闭包

 2023-09-06 阅读 15 评论 0

摘要:闭包的示例 什么是封包? (What are Closures?) A closure is the combination of a function and the lexical environment (scope) within which that function was declared. Closures are a fundamental and powerful property of Javascript. This article discuss

闭包的示例

什么是封包? (What are Closures?)

A closure is the combination of a function and the lexical environment (scope) within which that function was declared. Closures are a fundamental and powerful property of Javascript. This article discusses the ‘how’ and ‘why’ about Closures:

闭包是函数和在其中声明该函数的词法环境(范围)的组合。 闭包是Javascript的基本功能。 本文讨论了闭包的“方式”和“原因”:

(Example)

//we have an outer function named walk and an inner function named flyfunction walk (){var dist = '1780 feet';function fly(){console.log('At '+dist);}return fly;
}var flyFunc = walk(); //calling walk returns the fly function which is being assigned to flyFunc
//you would expect that once the walk function above is run
//you would think that JavaScript has gotten rid of the 'dist' varflyFunc(); //Logs out 'At 1780 feet'
//but you still can use the function as above 
//this is the power of closures

另一个例子 (Another Example)

function by(propName) {return function(a, b) {return a[propName] - b[propName];}
}const person1 = {name: 'joe', height: 72};
const person2 = {name: 'rob', height: 70};
const person3 = {name: 'nicholas', height: 66};const arr_ = [person1, person2, person3];const arr_sorted = arr_.sort(by('height')); // [ { name: 'nicholas', height: 66 }, { name: 'rob', height: 70 },{ name: 'joe', height: 72 } ]

The closure ‘remembers’ the environment in which it was created. This environment consists of any local variables that were in-scope at the time the closure was created.

闭包“记住”创建它的环境。 此环境由创建关闭时在范围内的所有局部变量组成。

function outside(num) {var rememberedVar = num; // In this example, rememberedVar is the lexical environment that the closure 'remembers'return function inside() { // This is the function which the closure 'remembers'console.log(rememberedVar)}
}var remember1 = outside(7); // remember1 is now a closure which contains rememberedVar = 7 in its lexical environment, and //the function 'inside'
var remember2 = outside(9); // remember2 is now a closure which contains rememberedVar = 9 in its lexical environment, and //the function 'inside'remember1(); // This now executes the function 'inside' which console.logs(rememberedVar) => 7
remember2(); // This now executes the function 'inside' which console.logs(rememberedVar) => 9

Closures are useful because they let you ‘remember’ data and then let you operate on that data through returned functions. This allows javascript to emulate private methods that are found in other programming languages. Private methods are useful for restricting access to code as well as managing your global namespace.

闭包很有用,因为它们可以让您“记住”数据,然后让您通过返回的函数对数据进行操作。 这允许javascript模拟其他编程语言中找到的私有方法。 私有方法对于限制对代码的访问以及管理全局名称空间很有用。

私有变量和方法 (Private variables and methods)

Closures can also be used to encapsulate private data/methods. Take a look at this example:

闭包也可以用于封装私有数据/方法。 看一下这个例子:

const bankAccount = (initialBalance) => {const balance = initialBalance;return {getBalance: function() {return balance;},deposit: function(amount) {balance += amount;return balance;},};
};const account = bankAccount(100);account.getBalance(); // 100
account.deposit(10); // 110

In this example, we won’t be able to access balance from anywhere outside of the bankAccount function, which means we’ve just created a private variable. Where’s the closure? Well, think about what bankAccount() is returning. It actually returns an Object with a bunch of functions inside it, and yet when we call account.getBalance(), the function is able to “remember” its initial reference to balance. That is the power of the closure, where a function “remembers” its lexical scope (compile time scope), even when the function is executed outside that lexical scope.

在此示例中,我们将无法从bankAccount函数之外的任何位置访问balance ,这意味着我们仅创建了一个私有变量。 封闭在哪里? 好吧,考虑一下bankAccount()返回什么。 实际上,它返回一个内部带有一堆函数的Object,但是当我们调用account.getBalance() ,该函数能够“记住”其对balance初始引用。 这就是闭包的强大之处,即使函数在该词法范围之外执行,函数也“记住”其词法范围(编译时范围)。

模拟块作用域变量。 (Emulating block-scoped variables.)

Javascript did not have a concept of block-scoped variables. Meaning that when defining a variable inside a forloop for example, this variable is visible from outside the forloop as well. So how can closures help us solve this problem ? Let’s take a look.

Javascript没有块范围变量的概念。 这意味着例如在forloop内定义变量时,也可以从forloop外部看到此变量。 那么闭包如何帮助我们解决这个问题呢? 让我们来看看。

var funcs = [];for(var i = 0; i < 3; i++){funcs[i] = function(){console.log('My value is ' + i);  //creating three different functions with different param values.}}for(var j = 0; j < 3; j++){funcs[j]();             // My value is 3// My value is 3// My value is 3}

Since the variable i does not have block-scope, it’s value within all three functions was updated with the loop counter and created malicious values. Closure can help us solve this issue by creating a snapshot of the environment the function was in when it was created, preserving its state.

由于变量i没有块作用域,因此使用循环计数器更新了这三个函数中的值并创建了恶意值。 闭包可以通过创建函数创建时所在的环境的快照,并保留其状态来帮助我们解决此问题。

var funcs = [];var createFunction = function(val){return function() {console.log("My value: " + val);};}for (var i = 0; i < 3; i++) {funcs[i] = createFunction(i);}for (var j = 0; j < 3; j++) {funcs[j]();                 // My value is 0// My value is 1// My value is 2}

The late versions of javascript es6+ have a new keyword called let which can be used to give the variable a blockscope. There are also many functions (forEach) and entire libraries (lodash.js) that are dedicated to solve such problems as the ones explained above. They can certainly boost your productivity, however it remains extremely important to have knowledge of all these issues when attempting to create something big.

javascript es6 +的较新版本有一个名为let的新关键字,可用于为变量赋予功能块。 还有许多函数(forEach)和整个库(lodash.js)专门用于解决上述问题。 它们当然可以提高您的生产率,但是在尝试创建大型产品时了解所有这些问题仍然非常重要。

Closures have many special applications that are useful when creating large javascript programs.

闭包有许多特殊的应用程序,在创建大型javascript程序时非常有用。

  1. Emulating private variables or encapsulation

    模拟私有变量或封装
  2. Making Asynchronous server side calls

    进行异步服务器端调用
  3. Creating a block-scoped variable.

    创建一个块作用域变量。

模拟私有变量。 (Emulating private variables.)

Unlike many other languages, Javascript does not have a mechanism which allows you to create encapsulated instance variables within an object. Having public instance variables can cause a lot of problems when building medium to large programs. However with closures, this problem can be mitigated.

与许多其他语言不同,Javascript没有允许您在对象内创建封装的实例变量的机制。 在构建中型到大型程序时,拥有公共实例变量会导致很多问题。 但是,使用闭包可以缓解此问题。

Much like in the previous example, you can build functions which return object literals with methods that have access to the object’s local variables without exposing them. Thus, making them effectively private.

与上一个示例非常相似,您可以构建函数,这些函数使用可以访问对象的局部变量而无需暴露它们的方法来返回对象文字。 因此,将它们有效地私有化。

Closures can also help you manage your global namespace to avoid collisions with globally shared data. Usually all global variables are shared between all scripts in your project, which will definitely give you alot of trouble when building medium to large programs. That is why library and module authors use closures to hide an entire module’s methods and data. This is called the module pattern, it uses an immediately invoked function expression which exports only certain functionality to the outside world, significantly reducing the amount of global references.

闭包还可以帮助您管理全局名称空间,以避免与全局共享数据发生冲突。 通常,所有全局变量都在项目中的所有脚本之间共享,这在构建中型到大型程序时肯定会给您带来很多麻烦。 这就是为什么库和模块作者使用闭包来隐藏整个模块的方法和数据的原因。 这称为模块模式,它使用立即调用的函数表达式,该函数表达式仅将某些功能导出到外界,从而大大减少了全局引用的数量。

Here’s a short sample of a module skeleton.

这是模块骨架的简短示例。

var myModule = (function() = {let privateVariable = 'I am a private variable';let method1 = function(){ console.log('I am method 1'); };let method2 = function(){ console.log('I am method 2, ', privateVariable); };return {method1: method1,method2: method2}
}());myModule.method1(); // I am method 1
myModule.method2(); // I am method 2, I am a private variable

Closures are useful for capturing new instances of private variables contained in the ‘remembered’ environment, and those variables can only be accessed through the returned function or methods.

闭包对于捕获“记住的”环境中包含的私有变量的新实例很有用,这些变量只能通过返回的函数或方法进行访问。

向量 (Vectors)

A vector is perhaps the most simple type of collection in Clojure. You can think of it like an array in Javascript. Let’s define a simple vector:

向量可能是Clojure中最简单的集合类型。 您可以将其视为Javascript中的数组。 让我们定义一个简单的向量:

(def a-vector [1 2 3 4 5])
;; Alternatively, use the vector function:
(def another-vector (vector 1 2 3 4 5))
;; You can use commas to separate items, since Clojure treats them as whitespace.
(def comma-vector [1, 2, 3, 4, 5])

You’ll see that it uses square brackets, just like an array in JS. Since Clojure, like JS, is dynamically typed, vectors can hold elements of any type, including other vectors.

您会看到它使用方括号,就像JS中的数组一样。 由于Clojure与JS类似,是动态类型化的,因​​此向量可以保存任何类型的元素,包括其他向量。

(def mixed-type-vector [1 "foo" :bar ["spam" 22] #"^baz$"])

向矢量添加项目 (Adding items to a vector)

You can append items to a vector using conj. You can also prepend to a list using into, but note that into is intended for merging two vectors, so both its arguments must be vectors, and using into is slower than using conj.

您可以使用conj将项目附加到向量。 您也可以在前面加上使用列表into ,但要注意, into适用于合并两个载体,所以它的两个参数必须是向量,并使用into比使用较慢的conj

(time (conj [1 2] 3))
; => "Elapsed time: 0.032206 msecs"
;    [1 2 3]
(time (into [1] [2 3]))
; => "Elapsed time: 0.078499 msecs"
;    [1 2 3]

IDEOne it!

IDEOne!

从向量中检索项目 (Retrieving items from a vector)

You can retrieve items from a vector using get. This is equivalent to using bracket notation to access items in an array in many imperative languages. Items in a vector are 0-indexed, counting from the left.

您可以使用get从向量中检索项目。 这等效于使用括号符号以许多命令式语言访问数组中的项目。 向量中的项从左开始数为0索引。

var arr = [1, 2, 3, 4, 5];
arr[0];
// => 1

In Clojure, this would be written like so:

在Clojure中,将这样写:

(def a-vector [1 2 3 4 5])
(get a-vector 0)
; => 1

You can also give get a default value, if you give it an index that isn’t in the array.

你也可以给get一个默认值,如果你给它一个指标,是不是在数组中。

;; the list doesn't have 2147483647 elements, so it'll return a string instead.
(get a-vector 2147483646 "sorry, not found!")
; => "sorry, not found!"

将其他集合转换为向量 (Converting other collections into vectors)

Non-vector data structures can be converted into vectors using the vec function. With hashmaps, this produces a 2D vector containing pairs of keys and values.

可以使用vec函数将非矢量数据结构转换为矢量。 使用哈希图,这将生成一个包含键和值对的2D向量。

(vec '(1 2 3 4 5))
; => [1 2 3 4 5]
(vec {:jack "black" :barry "white"})
; => [[:jack "black"] [:barry "white"]]

什么时候使用向量? (When to use a vector?)

A vector should be used in almost all cases if you need a collection, because they have the shortest random-access times, which makes it easy to retrieve items from a vector. Note that vectors are ordered. If order doesn’t matter, it may be better to use a set. Also note that vectors are designed for appending items; if you need to prepend items, you might want to use a list.

如果需要集合,几乎在所有情况下都应使用向量,因为它们具有最短的随机访问时间,这使得从向量中检索项目变得容易。 请注意,向量是有序的。 如果顺序无关紧要,则最好使用一组。 另请注意,矢量是为附加项目而设计的; 如果您需要添加项目,则可能需要使用列表。

有关封包的更多信息: (More info on Closures:)

  • Learn JavaScript closures in six minutes

    在六分钟内学习JavaScript关闭

  • A basic guide to closures in JavaScript

    JavaScript闭包的基本指南

  • Discover the power of closures in VueJS

    在VueJS中发现封闭的力量

  • JavaScript closures explained by mailing a package

    通过邮寄包裹解释JavaScript的关闭

翻译自: https://www.freecodecamp.org/news/closures-in-javascript-explained-with-examples/

闭包的示例

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/7074.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息