Heim > Artikel > Web-Frontend > Lassen Sie uns gemeinsam Verschlüsse kennenlernen
Verwandte Lernempfehlungen: Javascript-Video-Tutorial
Abschlüsse werden immer eine Hürde sein, die Front-End-Entwickler bei der Arbeit und in Interviews nicht umgehen können, ob es Ihnen gefällt oder nicht , wird angetroffen. Jeder hat ein anderes Verständnis von Schließung. Hier werde ich über mein eigenes Verständnis von Schließung sprechen. (Wenn es Unstimmigkeiten mit Ihrem Verständnis gibt, beziehen Sie sich bitte auf sich selbst)
Bevor Sie die Definition geben, können Sie sich auch ansehen, wie andere Abschlüsse definieren:
Funktionsobjekte können den Gültigkeitsbereich durchlaufen Ketten stehen in Beziehung zueinander und die Variablen innerhalb des Funktionskörpers können im Funktionsumfang gespeichert werden. Diese Funktion wird in der Informatikliteratur als „Abschluss“ bezeichnet – The Definitive Guide to JavaScript (6. Auflage)
Abschluss bedeutet A Funktion, die Zugriff auf Variablen im Gültigkeitsbereich einer anderen Funktion hat. Eine übliche Methode zum Erstellen eines Abschlusses besteht darin, eine Funktion innerhalb einer anderen Funktion zu erstellen. --Erweiterte Programmierung mit JavaScript (Dritte Ausgabe)
Ein Abschluss erfolgt, wenn sich eine Funktion an den lexikalischen Bereich erinnern und darauf zugreifen kann, in dem sie sich befindet, auch wenn die Funktion außerhalb des aktuellen lexikalischen Bereichs ausgeführt wird. -- JavaScript, das Sie nicht kennen (Band 1)
Obwohl die Beschreibungen in den obigen Absätzen unterschiedlich sind, können Sie nach sorgfältiger Verkostung dennoch einige Gemeinsamkeiten feststellen. Das Wichtigste ist die Verbindung zwischen verschiedenen Bereichen. Natürlich können Sie die obigen Definitionen direkt zitieren (schließlich sind die obigen Definitionen relativ maßgeblich). Hier bevorzugt der Autor die Definition im letzten Absatz und empfiehlt außerdem dringend das Buch „JavaScript You Don't Know“ (Band 1). )“, das es wert ist, sorgfältig und wiederholt gelesen zu werden.
Umfang und Umfangskette
Geltungsbereich: Eine Reihe von Regeln zum Suchen von Variablen nach Namen. In drei Typen unterteilt: globaler Bereich; Funktionsbereich; Was Sie beachten müssen, ist der Blockbereich, eine neue Spezifikation in ES6. Mit let, const
in geschweiften Klammern {}
definierte Variablen werden an den Gültigkeitsbereich gebunden und können außerhalb der geschweiften Klammern nicht aufgerufen werden.
Hinweis: Es gibt eine vorübergehende tote Zone
zwischen dem Anfang der geschweiften Klammern und vor der Deklaration der let-Variablen (dieser Punkt geht über den Rahmen dieses Artikels hinaus).
{}
里面使用let,const
定义的变量,都会绑定到该作用范围内,花括号以外的地方无法访问。注意:在花括号开始 到 let变量声明之前,存在暂时性死区
(该点不在本文讨论范围)。
作用域链:当不同的作用域 (混~淆~在~一~起~ 呸,不小心出戏了) 圈套在一起时,就形成了作用域链。注意的是,查找方向是从内到外的。
为什么作用域的查找方向是从内到外的呢?这是个很有趣的问题。个人觉得是跟js执行函数的入栈方式决定的(感觉有点偏题了,有兴趣的小伙伴可以去查一下资料)。
函数之所以 可以访问另一个函数作用域的变量(或者说记住当前的作用域并在当前以外的地方访问)的关键点
就是词法作用域
在起作用。这一点很重要,但不是所有人都知道这个知识点,这里简单探讨一下。
在编程界中,存在两种作用域工作模式,一种是被大多数编程语言所采用的
词法作用域
;另一种就是与其相反的动态作用域
(这个不在本文的讨论范围)。
词法作用域: 变量和块的作用域 在 您编写代码的阶段 就已经确定好了,不会随着调用的对象或者地方的不同而改变(感觉跟this相反)。
要不,举个栗子看看吧:
let a = 1; function fn(){ let a = 2; function fn2(){ console.log(a); } return fn2; } let fn3 = fn(); fn3();
从上面的定义可以知道,fn
是一个闭包函数,fn3
拿到了fn2
的指针地址,当fn3
执行的时候,其实是执行fn2
,而里面的a
变量,根据作用域链的查找规则,找到的是fn
作用域内的变量a
Scope-Kette: Wenn verschiedene Scopes zusammengeschlossen werden, entsteht eine Scope-Kette. Beachten Sie, dass die Suchrichtung von innen nach außen verläuft.
Der entscheidende Punkt bedeutet, dass der <code>lexikalische Bereich
am Werk ist. Das ist wichtig, aber nicht jeder kennt diesen Wissenspunkt. Lassen Sie uns ihn hier kurz besprechen.
In der Programmierwelt gibt es zwei Arbeitsmodi: Der eine ist der lexikalische Bereich
, der von den meisten Programmiersprachen verwendet wird; der andere ist der entgegengesetzte dynamische Bereich
(Dies würde den Rahmen dieses Artikels sprengen).
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的一个副作用, 如果当前词法作用域没有该属性,会在全局创建一个🎜 Aus der obigen Definition können wir erkennen, dass
fn
eine Abschlussfunktion ist und fn3
erhält Die Zeigeradresse Wenn <code>fn3
ausgeführt wird, führt fn2 tatsächlich fn2
und die darin enthaltene Variable a
entsprechend dem Suchbereich aus Die Regel der Kette findet die Variable a
im Bereich von fn
, sodass die endgültige Ausgabe 2 und nicht 1 ist. (Sie können das Bild unten sehen)🎜🎜🎜🎜🎜🎜🎜Off-Topic: Wie kann man den lexikalischen Umfang betrügen? 🎜🎜Obwohl der lexikalische Umfang statisch ist, gibt es dennoch Möglichkeiten, ihn auszutricksen, um dynamische Effekte zu erzielen. 🎜第一种方法是使用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培训栏目!
Das obige ist der detaillierte Inhalt vonLassen Sie uns gemeinsam Verschlüsse kennenlernen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!