javascript之闭包_javascript闭包

javascript之闭包

A Closure is a combination of function and lexical environment where this function was declared. The environment may consist of both local variables declared in the body of a function and global ones declared outside of the function. To put it in an equation, Closure equals function plus lexical environment (for instance, local variables, global variables, outer functions) within which that function was declared.

闭包是函数和声明此函数的词法环境的组合。 环境可能包含在函数主体中声明的局部变量和在函数外部声明的全局变量。 为了将其放在等式中,闭包等于函数加上在其中声明该函数的词法环境(例如,局部变量,全局变量,外部函数)。

If you keep your mind open and have no prejudices, at the end of this article we’ll grasp the idea and practical implementation of closures.

如果您保持开放的态度并且没有偏见,那么在本文结尾,我们将了解闭包的思想和实际实现。

The below example shows that the inner anonymous function has access to the local variable double out of its scope (lexical scope). We bind this function to different variables outside of this scope and each time we call them, we can pass different values as arguments. As soon as the anonymous function has access to the inner variable double, it can now take both this variable value and passed the argument and make simple calculations (val * double).

下面的例子示出内匿名功能可以访问本地变量出其范围(词法范围)的。 我们将此函数绑定到该范围之外的其他变量,每次调用它们时,我们都可以将不同的值作为参数传递。 一旦匿名函数可以访问内部变量double,它现在就可以同时获取此变量值和参数,并进行简单的计算( val * double )。

function simpleDoubler(){
let double = 2; // local variable of lexical environment
return function (val){
return val * double;
}
}let doubleFour = simpleDoubler();
let doubleTen = simpleDoubler();
console.log(doubleFour(4)); // 8
console.log(doubleTen(10)); // 20

Each time, when we console log simpleDoubler function and pass the desired integer to be doubled, it performs these operations written in the body of the function. Another implementation to consider:

每次,当我们控制台记录simpleDoubler函数的日志并传递要加倍的所需整数时,它将执行写在函数主体中的这些操作。 要考虑的另一个实现:

let colorChanger = (function() {
return function change(color) {
console.log({color});
}})();let red = colorChanger('red');
let green = colorChanger('green');
let orange = colorChanger('orange');

In the example above we created a function named colorChanger which returns another function that we can pass an argument into. Our inner function logs in the console an object with object property shorthand syntactic sugar (a feature available with ES6/ES2015) where, if the key and value have the same value (for instance, {color: color}), we can avoid duplication by simply passing the name of value ({color}). An important thing to notice here is that this is IIFE (Immediately Invoked Function Expression) which runs as soon as it’s declared, by passing both functions into parentheses and invoking them right after it (again, with parentheses), thus being invoked right after it was created.

在上面的示例中,我们创建了一个名为colorChanger的函数,该函数返回另一个可以传递参数的函数。 我们的内部函数将带有对象属性速记语法糖(ES6 / ES2015中提供的功能)的对象登录到控制台,如果键和值具有相同的值(例如{color:color} ),则可以避免重复只需传递值的名称({color})。 这里要注意的重要一点是,这是IIFE (立即调用的函数表达式),它在声明后立即运行,将两个函数都传递给括号并在其后立即调用它们(再次带括号),从而在其后立即被调用已创建。

let country = (() => {
return (name) => {
return (capital) => {
return (language) => {
return (population) => {
console.log(`country: ${name}, capital: ${capital}, language: ${language}, population: ${population}`);
if (population < 3000000) {
console.log('small population');
} else if (population >= 3000000 && population <= 100000000) {
console.log('mid-size population');
} else {
console.log('large population');
}
};
};
};
};
})();let malta = country('Malta')('Valletta')('Maltese')(514564);
let france = country('France')('Paris')('French')(65273511);
let usa = country('USA')('Washington')('English')(331002651);

The example above is a bit more complicated. There is a whole hierarchy of nested functions, but we’ll be ok as soon as we remember the most important thing in Closures, that the deeper the scope is the more it has access to the outer scopes. This means that the anonymous arrow function that takes the population as an argument has access to all arguments passed in the outer functions before (language, then capital, then name). After writing the country function we need to bind it to different variables like malta, france, and usa. The argument sequence that we pass into country function is also important. First, in parentheses, we pass string Malta, then string Valletta, then string Maltese, then integer 514564 (which is an actual population of Malta island at the time this article is written). They represent the name, capital, language, and population placeholders, respectively (this is why the sequence is important). The if statement in the code may seem fully optional at first glance since it provides an additional sorting by population size, but if we only try to cut and paste this condition anywhere outside its present scope (the core, the deepest scope), it will give as an error (Uncaught ReferenceError: population is not defined), complaining that the population is not visible while it is referenced outside but was created inside! This proves the concept of the Closures that only the inner scope has access to all the data (variables, arguments) of the lexical environment and not the other way round!

上面的示例有点复杂。 嵌套函数有一个完整的层次结构,但只要记住Closures中最重要的内容,我们就可以了,范围越深,就越能访问外部范围。 这意味着将填充作为参数的匿名箭头函数可以访问之前在外部函数中传递的所有参数( 语言,然后是大写 字母 然后是name )。 编写国家/地区函数后,我们需要将其绑定到不同的变量,例如马耳他法国美国 。 我们传递给国家功能的论证顺序也很重要。 首先,在括号中,我们传递字符串Malta ,然后传递字符串Valletta ,然后传递字符串Maltese ,然后传递整数 514564(这是撰写本文时马耳他岛的实际人口)。 它们分别代表名称大写 字母语言人口占位符(这就是顺序很重要的原因)。 乍看之下,代码中的if语句似乎完全是可选的,因为它提供了按总体大小进行的其他排序,但是如果我们仅尝试将此条件剪切并粘贴到其当前范围(核心,最深范围)之外的任何位置,给出错误(Uncaught ReferenceError:未定义填充 ),抱怨填充在外部被引用但在内部创建时不可见! 这证明了Closures的概念,即只有内部范围才可以访问词汇环境的所有数据(变量,自变量),而不是相反!

let country = (() => {
if (population < 3000000) {
console.log('small population');
} else if (population >= 3000000 && population <= 100000000) {
console.log('mid-size population');
} else {
console.log('large population');
}
return (name) => {
return (capital) => {
return (language) => {
return (population) => {
console.log(`country: ${name}, capital: ${capital}, language: ${language}, population: ${population}`);
};
};
};
};
})();let malta = country('Malta')('Valletta')('Maltese')(514564);
let france = country('France')('Paris')('French')(65273511);
let usa = country('USA')('Washington')('English')(331002651);
// Uncaught ReferenceError: population is not defined

Conclusion

结论

Although many JavaScript developers use Closures instinctively or based on experience, it would be better if we understand the concept to be more consequent, reasonable, and confident. The deeper scope has access to more superficial one, or inner has access to outer. From now on, as you already went through one of the hardest parts in JavaScript, nothing should hold you down in your journey to uncover all the secrets and beauty of this scripting language and get the most out of one of its quirky parts called Closures.

尽管许多JavaScript开发人员本能地或基于经验来使用Closures,但是如果我们理解该概念更具有结果性,合理性和自信性,那就更好了。 较深的范围可以访问更肤浅的范围,或者内部可以访问外部 。 从现在开始,您已经经历了JavaScript中最困难的部分之一,因此,没有什么可以阻止您发现此脚本语言的所有秘密和美丽,并从其古怪的部分(称为Closures)中获得最大收益。

翻译自: https://medium.com/swlh/javascript-closures-1cd5e45e0790

javascript之闭包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值