闭包的示例
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的基本功能。 本文讨论了闭包的“方式”和“原因”:
//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
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模拟其他编程语言中找到的私有方法。 私有方法对于限制对代码的访问以及管理全局名称空间很有用。
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
初始引用。 这就是闭包的强大之处,即使函数在该词法范围之外执行,函数也“记住”其词法范围(编译时范围)。
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程序时非常有用。
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.
闭包对于捕获“记住的”环境中包含的私有变量的新实例很有用,这些变量只能通过返回的函数或方法进行访问。
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$"])
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!
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!"
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"]]
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.
如果需要集合,几乎在所有情况下都应使用向量,因为它们具有最短的随机访问时间,这使得从向量中检索项目变得容易。 请注意,向量是有序的。 如果顺序无关紧要,则最好使用一组。 另请注意,矢量是为附加项目而设计的; 如果您需要添加项目,则可能需要使用列表。
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/
闭包的示例
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态