Heim >Web-Frontend >js-Tutorial >Verständnis der tatsächlichen Parameter, formalen Parameter und Abschlüsse von js-Funktionen
Dieser Artikel führt hauptsächlich in das Verständnis tatsächlicher Parameter, formaler Parameter und Schließungen von js-Funktionen ein. Er hat einen bestimmten Referenzwert. Jetzt können Freunde in Not darauf verweisen.
if(a === undefined) a = [];
ist äquivalent zu
a = a || [];
Diese beiden Sätze sind völlig gleichwertig, mit der Ausnahme, dass letzterer im Voraus a deklarieren muss
Wenn der Parameter nicht übergeben wird, erfolgt der Rest ausgefüllter undefinierter
optionaler formaler Parameter: Verwenden Sie den Kommentar /optional/, um hervorzuheben, dass der Parameter optional ist, und fügen Sie ihn am Ende ein, andernfalls wird null oder undefiniert als Platzhalter für die Übergabe von Enter verwendet
Aufgerufener bezieht sich auf die Funktion, die gerade ausgeführt wird
Aufrufer bezieht sich auf die Funktion, die die Funktion derzeit ausführt
> > function e(o){ ... return o.Object; ... } undefined > e; [Function: e] > var a = {Object:33}; undefined > e(a); 33 >
Funktion kann als Wert an eine andere Funktion übergeben werden
Funktion Attribute können angepasst werden
o.a = 3; function o() { return o.a; }
In der Funktion deklarierte Variablen sind im gesamten Funktionskörper sichtbar (einschließlich innerhalb verschachtelter Funktionen), nicht jedoch außerhalb der Funktion sichtbar. Variablen, die nicht innerhalb einer Funktion deklariert sind, sind globale Variablen. Es ist im gesamten js-Programm sichtbar. In js können Sie keine Variablen deklarieren, die nur innerhalb eines Codeblocks sichtbar sind. Daher ist es oft einfach, eine Funktion zu definieren, die als temporärer Namespace verwendet werden soll. Innerhalb dieses Namensraums definierte Variablen belasten den globalen Namensraum nicht.
Das liegt genau daran, dass es zu einer Variablenverschmutzung kommt, wenn Variablen global definiert werden und globale Variablen verunreinigt werden (naja, das ist eine Falle dynamischer Sprachen), was zu einigen unbekannten Fehlern führt. Daher wird das Platzieren der Variablen in der Funktion und deren Aufruf ihren globalen Raum verschmutzen und zu Variablenkonflikten führen (insbesondere in der Browserumgebung kann es leicht zu verschiedenen unbekannten Fehlern kommen, daher muss dies so sein)
( function() { return 333; }() );
Das Hinzufügen von () ist erforderlich, denn wenn Sie () nicht hinzufügen, denkt der JS-Interpreter, dass es sich um eine Funktionsdeklaration handelt, und die Funktion wird als deklariert Funktion Zur Erläuterung lässt der js-Interpreter die Erstellung einer anonymen Funktionsdeklaration nicht zu, sodass ein Fehler gemeldet wird.
Fügen Sie () hinzu, um einen Funktionsausdruck zu werden, und führen Sie den JS-Interpreter aus, um einen anonymen Funktionsausdruck zu erstellen
Endlich ist der Abschluss erreicht. (Schwerwiegender Punkt Σ( ° △ °|||)︴)
(Dies ist der schwierigste Teil, die Grundlage der funktionalen Programmierung und der kritischste Teil dafür, ob Sie js gut lernen können ... Natürlich, es6 Es gibt auch eine lästige Pfeilfunktion.)
Der Abschluss ist eine wichtige Grundlage für die funktionale Programmierung.
Wie andere Sprachen übernimmt auch js den lexikalischen Bereich, das heißt, die Ausführung der Funktion hängt vom Bereich der Variablen ab Wird bestimmt, wenn die Funktion definiert wird, nicht, wenn sie aufgerufen wird
Das heißt, der interne Status des Funktionsobjekts von js enthält nicht nur die Codelogik der Funktion, sondern muss sich auch auf die aktuelle Bereichskette (den Bereich von) beziehen Die Variable ist nach unten gerichtet.) Passiv, die Gültigkeitskette der Variablen wird bei der Suche nach oben durchsucht, bis zum oberen Rand der Funktion.) Funktionsobjekte können über die Gültigkeitskette miteinander in Beziehung gesetzt werden. Variablen innerhalb des Funktionskörpers können gespeichert werden im Funktionsbereich , das heißt, Abschluss
ist ein alter Begriff, der bedeutet, dass Funktionsvariablen innerhalb der Bereichskette ausgeblendet werden können, sodass es den Anschein hat, dass die Funktion die Variablen umschließt.
Die Bereichskette ist eine Liste von Objekten. Jedes Mal, wenn eine js-Funktion aufgerufen wird, wird ein neues Objekt erstellt, um seine lokalen Variablen zu speichern Wenn die Funktion zurückkehrt, wird das gebundene Objekt aus der Bereichskette gelöscht. Wenn keine verschachtelte Funktion vorhanden ist und kein Verweis auf das gebundene Objekt vorhanden ist, wird es vom js-Interpreter als Müll erfasst ist unregelmäßig und löscht es nicht sofort, wenn es nicht vollständig referenziert ist. Wenn verschachtelte Funktionen definiert sind, entspricht jede verschachtelte Funktion einer Bereichskette, und diese Bereichskette zeigt auf eine Variable Das gebundene Objekt. Wenn diese verschachtelten Funktionsobjekte in der äußeren Funktion gespeichert werden, werden sie ebenso wie die Variablenbindungsobjekte, auf die sie verweisen, durch Müll gesammelt, wenn die Funktion die verschachtelte Funktion definiert und als Rückgabewert zurückgibt oder wenn sie in einem bestimmten Attribut gespeichert wird. Es gibt einen externen Verweis, der auf diese verschachtelte Funktion verweist. Das heißt, sie wird nicht als Garbage Collection behandelt und das an ihre Variable gebundene Objekt wird nicht als Garbage Collection behandelt.
Nachdem die Funktion ausgeführt wurde, wird die entsprechende Bereichskette nicht gelöscht. Der Löschvorgang wird nur ausgeführt, wenn keine Referenz mehr vorhanden ist.
Originalstapel
Fenster oben auf dem Stapel
Führen Sie das folgende js-Skript aus
function a() { function f() { return 333; } return f; } a()();
栈顶 a → window
开始调用,执行到return
发现需要调用f
继续加栈
栈顶 f → a → window
执行完f弹出f
继续执行a,执行完毕弹出a
最后全部执行完毕弹出window
算了文字解释太无力,直接上代码
var scope = "global scope"; // 一个全局变量 function checkscope() { var scope = "local scope"; // 定义一个局部变量 function f() { return scope; // 返回变量作用域中的scope的值 } return f(); // 返回这个函数 }
调用一下这个函数
checkscope(); "local scope"
接着这样执行
var scope = "global scope"; // 一个全局变量 function checkscope() { var scope = "local scope"; // 定义一个局部变量 function f() { return scope; // 返回变量作用域中的scope的值 } return f; // 返回这个函数 }
继续调用函数
checkscope()(); "local scope"
先看一个函数uniqueInteger()使用这个函数能够跟踪上次的返回值
var uniqueInteger = ( function() { var count = 0; return function() {return count++} }() );
这样子就使用闭包
uniqueInteger(); 0 uniqueInteger(); 1
每次返回是其上一次的值,并随便直接将值加1
至于为什么要这样写,如果不使用闭包,那么恶意代码就可以随便的将计数器重置了。。
uniqueInteger.count = 0; function uniqueInteger() { return uniqueInteger.count++; }
类似这样的,完全可以做到直接通过赋值,将其count的值重置。
而如果使用闭包,没有办法进行修改,为私有状态,也不会导致其一个页面内变量的冲突,或者是其覆盖。
var a = (function c(){ var a = 1; a++; console.log('已经执行'); return function b(){return a++}; }())
额,我大概解释一下这段代码。
首先呢,解释最外层的圆括号,因为如果没有圆括号,则这个是一个赋值语句,将一个匿名函数赋值给变量a,实际上是在内存中完成了栈中变量a指向匿名函数存储的空间的地址,如果有圆括号,实际上是告诉js解释器这是一个语句,需要js执行,消除了其function带来的影响。(ps;貌似火狐上不加也可以,也可以正常的运行)执行和引用的关系下方有。
然后呢,最后的圆括号,代表着其执行这个函数,因为js解析器将()解析为调用前方的函数名称,类似于运算符吧。但是实际上并不是运算符,因为能往其内传值,注意,这点是将其执行的结果保存在堆中,并完成其指向
其后,当直接输入a;,实际上执行并完成了一次调用,其返回值为函数b,将函数b完成一次引用,即变量a引用函数b,由于其存在引用关系,即栈中变量a保存的为其函数a的返回结果,(因为其不是不是对象,如果写a()()表示将函数a调用后返回的对象保存在栈中,然后将栈中的内容再次调用,由于是保存,并不存在其应用关系,所以执行完毕后直接垃圾回收)由于其保存的是函数b的作用域链,而函数b的作用域链是继承自函数a的作用域链,但是由于函数a的作用域链并没有引用导致其执行完后被垃圾回收(当不在有变量指向的时候)。所以呢,函数其值是在函数b中进行保存,如果修改函数c此时函数c并不会影响到函数b中的保存,因为其函数c的变量列表已被销毁,
最后,继续讨论起嵌套函数的引用,由于其父函数已被销毁,但是嵌套函数被引用,(注意:因为其父已经没有,所以是另开辟一块新的堆空间,用于存储其函数c的返回结果,注意是返回结果,而不是函数b)此时另外指定变量保存其结果,无论指定多少个变量保存其结果,都是新的空间的执行,没有任何的干扰,详细了解看下面,继续讨论
ps;如果是()()则代表其会被其垃圾回收
ps 还需要注意一点点的是由于其引用的是result的值,并不是其
最后,这样就能完成其变量保存在函数中,貌似叫做记忆?
所以呢,借助堆和栈就很好的能理解了闭包
function count() { var n = 0; return { count: function() { return n++; }, reset: function() { n = 0; } }; }
var c = count(); var d = count(); undefined
在分别执行一下下
c.count(); 0 d.count(); 0 c.count(); 1 d.count(); 1 c.reset(); undefined c.count(); 0 d.count(); 2
这一点体现了其互不影响性,表明其由于其父被回收,导致其子分别开创了一块在堆中新的内存空间,并完成其指向,互相不干扰。
其作用域链互不干扰
function count(n) { return { get count() { return n++; }, set count(m) { if ( m >= n) n = m; else throw new Error( '请输入一个正确的值' ); }, }; }
这个就不用解释啦,很简单啦
function test1() { val = value = 111; this.test = function() { return value - 1; }; this.test2 = function() { return value + 1; }; }
这同样是两个作用链域
不过这样写需要先执行其o.test1(),因为其方法在其函数内部,必须先执行一下,完成其方法的添加,否则会报错,
ee.test is not a function
提示找不到这个方法,
因为执行
ee.test1 = test1; function test1()
只是简单的进行赋值,并不能进行查看,所以导致其无法使用
所以嘛,要先执行一遍,让其方法添加进去
ee.test1(); undefined ee.test(); 110 ee.test2(); 112
这就是两个闭包,这两个闭包互相平行,同时继承于其父,但是又不受其父影响,很神奇吧,(@ο@)
叮 又发现一个莫名奇妙的东东 https://us.leancloud.cn 貌似目前水平能看懂一些了
this在父闭包显示的即为使用该方法的对象。
但是子就不一定了。
function test1() { val = value = 111; this.test = function() { return this.x - 1; }; this.test2 = function() { return this.x + 1; }; }
执行一下
ee.test(); 4443
这就尴尬了。
好吧。只能说是一般不这样用
一般这样写
var self = this;
将其值保存进一个self中
相关推荐:
Das obige ist der detaillierte Inhalt vonVerständnis der tatsächlichen Parameter, formalen Parameter und Abschlüsse von js-Funktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!