Home > Article > Web Front-end > Let’s get to know closures together
Related learning recommendations: javascript video tutorial
## Closure is always a hurdle that front-end developers cannot get around. Whether you like it or not, you will encounter it at work and in interviews. Everyone's understanding of closure is different. Here I will talk about my own understanding of closure. (If there is any discrepancy with your understanding, please refer to yourself)
How to define closureBefore giving the definition, you may wish to take a look at how others define closure:Function objects can be related to each other through scope chains, and variables inside the function body can be saved in the function scope. This feature is called "closure" in computer science literature - JavaScript authority Guide (Sixth Edition)
#A closure is a function that has access to a variable in the scope of another function. A common way to create a closure is to create a function inside another function. --Advanced Programming in JavaScript (Third Edition)
A closure occurs when a function can remember and access the lexical scope it is in, even if the function is in the current lexical scope Execution outside the domain. -- JavaScript You Don't Know (Volume 1)Although the descriptions in the above paragraphs are not the same, you can still find some commonalities after you taste them carefully. The most important of these is the
connection between different scopes. Of course, you can directly quote the above definitions (after all, the above definitions are relatively authoritative). Here, the author prefers the definition in the last paragraph and strongly recommends the book "JavaScript You Don't Know (Volume 1)", which is worth Read carefully and repeatedly.
What knowledge points are involved in closureIt is not enough to just give a definition, you must also explore what knowledge points are involved internally. The following are the knowledge points that the author thinks are useful. Scope and scope chainWell, in fact, the author knows that you have all thought of this (no, no one has not thought of this). Now that everyone knowsscope. Here I will briefly describe it and go through the process.
Scope: A set of rules for finding variables by name. Divided into three types: global scope; function scope; block scope.What needs to be noted is block scope, a new specification in ES6. Variables defined using
let and const inside the curly braces
{} will be bound to the scope and cannot be accessed outside the curly braces.
Note: There is a temporary dead zone between the beginning of the curly braces and before the let variable declaration (this point is beyond the scope of this article).
Scope chain: When different scopes are trapped together, a scope chain is formed. Note that the search direction is from inside to outside.Why is the search direction of the scope from inside to outside? This is an interesting question. Personally, I think it is determined by the way in which js execution functions are pushed into the stack (it feels a bit off topic, interested friends can check the information). Lexical scopeThe key point why a function can access variables in another function scope (or remember the current scope and access it outside the current one)
is lexical scope
at work. This is very important, but not everyone knows this knowledge point. Let’s briefly discuss it here.
lexical scopeLexical scope: The scope of variables and blocks has been determined when you write the code, and will not change with the object or place where it is called (it feels like This is the opposite).used by most programming languages; the other is the opposite.
Dynamic Scope
(This is beyond the scope of this article).
Otherwise, let’s give an example:
let a = 1; function fn(){ let a = 2; function fn2(){ console.log(a); } return fn2; } let fn3 = fn(); fn3();
From the above definition, we can know that
fn is a closure function, fn3
got the pointer address of fn2
. When fn3
is executed, fn2
is actually executed, and the a
variable inside, According to the search rules of the scope chain, what is found is the variable a
in the fn
scope, so the final output is 2, not 1. (You can see the picture below)
第一种方法是使用eval. eval可以把字符串解析成一个脚本来运行,由于在词法分析阶段,无法预测eval运行的脚本,所以不会对其进行优化分析。
第二种方法是with. with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。with本身比较难掌握,使用不当容易出现意外情况(如下例子),不推荐使用 -.-
function Fn(obj){ with(obj){ a = 2; } } var o1 = { a:1 } var o2 = { b:1 } Fn(o1); console.log(o1.a); //2 Fn(o2); console.log(o2.a); //undefined; console.log(a); //2 a被泄漏到全局里面去了 // 这是with的一个副作用, 如果当前词法作用域没有该属性,会在全局创建一个
闭包的使用场景可多了,平时使用的插件或者框架,基本上都有闭包的身影,可能您没留意过罢了。下面笔者列举一些比较常见的场景。
模拟私有变量和方法,进一步来说可以是模拟模块化
;目前常用的AMD,CommonJS等模块规范,都是利用闭包的思想;
柯里化函数或者偏函数;利用闭包可以把参数分成多次传参。如下面代码:
// 柯里化函数 function currying(fn){ var allArgs = []; function bindCurry(){ var args = [].slice.call(arguments); allArgs = allArgs.concat(args); return bindCurry; } bindCurry.toString = function(){ return fn.apply(null, allArgs); }; return bindCurry; }
实现防抖或者节流函数;
实现缓存结果(记忆化)的辅助函数:
// 该方法适合缓存结果不易改变的函数 const memorize = fn => { let memorized = false; let result = undefined; return (...args) => { if (memorized) { return result; } else { result = fn.apply(null,args); memorized = true; fn = undefined; return result; } }; };
说了那么多,我怎么知道自己写的代码是不是闭包呢?先不说新手,有些代码的确隐藏的深,老鸟不仔细看也可能发现不了。 那有没有方法可以帮助我们区分一个函数是不是闭包呢?答案是肯定的,要学会善于利用周边的工具资源,比如浏览器。
打开常用的浏览器(chrome或者其他),在要验证的代码中打上debugger断点,然后看控制台,在scope里面的Closure(闭包)里面是否有该函数(如下图)。
答案是有可能。内存泄漏的原因在于垃圾回收(GC)无法释放变量的内存,导致运行一段时候后,可用内存越来越少,最终出现内存泄漏的情况。常见的内存泄漏场景有4种:全局变量;闭包引用;DOM事件绑定;不合理使用缓存。其中,闭包导致内存泄漏都是比较隐蔽的,用肉眼查看代码判断是比较难,我们可用借助chrome浏览器的Memory标签栏工具来调试。由于篇幅问题,不展开说明了,有兴趣自己去了解一下如何使用。
想了解更多编程学习,敬请关注php培训栏目!
The above is the detailed content of Let’s get to know closures together. For more information, please follow other related articles on the PHP Chinese website!