每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,歡迎關注開源日報。交流QQ群:202790710;微博:https://weibo.com/openingsource;電報群 https://t.me/OpeningSourceOrg
今日推薦開源項目:《提升網頁性能的方法 Front-End-Performance-Checklist》傳送門:GitHub鏈接
推薦理由:這個項目中主要介紹的是如何在前端這一塊提升網頁的性能,主要從 HTML,CSS,字體,圖片,JS,服務和 JS 框架方面展開,提升性能不應該總是後端的事情,前端寫的好一樣可以達到這個目的。
今日推薦英文原文:《Closures Explained, Simply》作者:Daniel Lempesis
原文鏈接:https://medium.com/@daniellempesis/closures-explained-simply-e83680793e4f
推薦理由:顧名思義,簡單介紹了關於 JS 中閉包的概念
Closures Explained, Simply
One of the most widely-covered, important topics in JavaScript is the concept of closures. You certainly hear about them a lot. You may have even been asked to explain what they are in an interview. Of all the explanations I』ve read, though, none have been newbie-friendly, and many have been downright confusing.
I』ll be honest: When I first tried learning about closures, I had absolutely no idea what the explanations I was reading were trying to say. Many seem to be riddled with unclear pronoun references and suffer from gross overuse of the word 「function」. I realized only much later I』d been using them for months; closures just seemed like a logical extension of what I』d already been doing, and I hadn』t given it a single thought, much less known there was a special name for what I』d been doing.
Diving In
Closures are actually an incredibly simple concept. If you already have a basic understanding of how JavaScript』s scope works, it』s going to be a breeze. If not, it will be a little more complicated, but still not too hard.
I like to use the word 「enclosure」 when explaining closures, because in a sense a closure both exists in an enclosure (its parent function) and is an enclosure itself: Housing its own variables and potentially its own closures, everything inside of it is invisible to the rest of your application.
A JavaScript closure is, very simply, any function that exists inside another function. It looks like any other function, and requires no special steps to 『turn it into』 a closure, except that it must exist within another function. It may be declared with function
, or with const
, or if you』re feeling nostalgic, with var
. (It even works with new Function
if you so desire.)
A closure has, perhaps unsurprisingly, full access to any variables declared within itself. It also has, due to the nature of JavaScript』s scope, access to any variable or function which exists in either the global scope, or in the hierarchy of functions within which it is nested. Conversely, all variables and any functions inside the closure (this would make them closures as well) are inaccessible to any function the closure is inside of, in addition to being inaccessible to anything in the global scope.
Below is a non-generic example of a closure, finding all the prime numbers between 2 and 17; the closure itself is in bold.
Note that to keep things as simple as possible so brand new coders (or those coming from languages like Python or Ruby) can easily follow, I』m implementing the simplest (and slowest) prime solver I know how to, declaring the numbers 1–17 as an array, and using a
while
loop with more Python/Ruby-like syntax. This implementation is in no way recommended 🙂
function primesUpToSeventeen() { const numbers = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]; const primes = [];
function isPrime(number) { //this is our closure. if (number < 2) return false; else if (number === 2) return true;
let divisor = 2;
while (divisor < number) { if (number%divisor === 0) return false; else divisor += 1 }; return true };
numbers.forEach(number=> { if (isPrime(number)) //isPrime() closure is being called here primes.push(number) }); return primes };
//returns [2, 3, 5, 7, 11, 13, 17]
In the above example, isPrime()
is a closure function housed within its parent function, primesUpToSeventeen().
Its parent doesn』t know or care what』s happening inside of isPrime()
; it doesn』t know anything about its internal variables, what functions (closures!) it may contain (in this case, it doesn』t have any), or even if there are variables declared inside isPrime()
which share names with variables in primesUpToSeventeen()
's own scope. All it knows is what isPrime()
tells it when it completes its work; in this case,isPrime()
is going to return either true
or false
. That』s all its parent function really knows.*
So, so far so good; we』re getting somewhere. But the above function is actually a pretty unhelpful example. We could move isPrime()
out of primesUpToSeventeen()
like this:
function primesUpToSeventeen() { //primesUpToSeventeen() without isPrime() code here }
function isPrime(number) { //isPrime code here }
…and it would behave identically.
Let』s do just that, and then add another step to demonstrate one of the concepts we』ve covered so far: that a closure has access to any variable in any of the functions it』s nested in. Here, we』ll only return numbers if a.) they』re prime, and b.) the result of adding 6 to them is also prime. This is a bit contrived for the sake of keeping it simple and illustrating this concept, so just pretend our addition is some highly complicated function doing interesting work on the numbers it receives.
function isPrime(number) { //exists in global scope; not a closure //...code here };
function plusSixPrimesUpToSeventeen() { //our outer function const numbers = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]; const primes = [];
numbers.forEach(number=> { //add primes we find to primes array if (isPrime(number)) primes.push(number) });
function findPlusSixPrimes() { //this is our closure const plusSixPrimes = [];
primes.forEach(prime=> { const primePlusSix = prime + 6
if (isPrime(primePlusSix)) { plusSixPrimes.push(prime) }; }); return plusSixPrimes };
return findPlusSixPrimes() //we call our closure here };
//returns [5, 7, 11, 13, 17] because 11, 13, 17, 19 and 23 are prime
Notice we didn』t pass any variables to our closure. We didn』t have to; isPrime()
exists in the global scope, so our closure can use it whenever it wants, and the primes
array we populated earlier at the top of our main (「outer」) function (plusSixPrimesUpToSeventeen()
) exists in the same space (scope) our closure does.
And that』s pretty much it! Closures have many uses not covered here, but you now understand what they are and how they work.
*Note that this does not hold true for reassignment; declaring a variable within a closure, even a variable with a name already used outside of the closure will not result in any namespace issues; however, reassigning or mutating a variable (e.g. numbers = []
or numbers.length = 0
) will modify that outer variable. In this particular case, numbers can』t be reassigned anyway as it』s a constant, and even if it weren』t, I used a forEach
loop, so reassigning numbers
wouldn』t actually affect the function』s output. But it』s important to remember that closures absolutely can modify any variable it has access to (which is a good thing!).
每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,歡迎關注開源日報。交流QQ群:202790710;微博:https://weibo.com/openingsource;電報群 https://t.me/OpeningSourceOrg