Einführung
JavaScript ist eine Full-Stack-Sprache. Besonders im Jahr 2016 höre ich oft Gerüchte, dass JavaScript die Welt dominieren wird, und es gibt sogar Gerüchte Es heißt, dass man im Jahr 2016 einen Job finden kann, wenn man Vue.js kennt, genauso wie man damals einen Job finden kann, wenn man TableView auf iOS kennt (tableView entspricht ListView von Android, aber jetzt wird im Grunde RecyclerView verwendet).
2016 Die beliebten Front-End-Technologien hängen im Wesentlichen mit JavaScript zusammen, beispielsweise die mobile plattformübergreifende Plattform React Native von Facebook und Alibabas Weex, die Hot-Repair-Technologie JSPath und das Back-End Node.js ( Ein Technologie-Stack, der mir sehr gut gefällt. Gestern bin ich zu Gibhub gegangen und habe einen Blick darauf geworfen. Die Anzahl der Sterne hat die von jQuery übertroffen, aber zumindest haben wir das gesehen Das Front-End-Denken hat sich von der vorherigen Dokumentoperation zur datengesteuerten Entwicklung geändert (wenn Sie interessiert sind). Ich kann Android, iOS und Vue später kombinieren, um diese Änderung im Denken mithilfe einer kleinen Demo zu demonstrieren zu versuchen, Element von Ele.me zu verwenden, um EasyUI zu ersetzen (Studenten, die Back-End-Arbeit geleistet haben, sollten wissen, dass EasyUI wirklich eine AV-Malereiqualität ist ...)
JS-Technologien tauchen nacheinander auf Es gab bereits einen sehr beliebten Artikel darüber, wie es war, JS im Jahr 2016 zu lernen. Es hat vielen Leuten Angst gemacht. Wenn es um Frameworks und neue Technologien geht, wurde natives JS ausgelassen um einige grundlegende JS-Probleme mit allen zu teilen
Bereich in JavaScript
Das Folgende ist eine einfache Frage:
<script> var str1 = "hello"; var str2 = "world"; function t1() { console.log(str1); console.log(str2); var str2 = "toby"; console.log(str2); } //这里会输出什么? t1(); </script>
Dies ist ein sehr einfaches JS Scope-Problem, aber je mehr Sie das Wort „einfach“ betonen, desto leichter fällt es den Menschen, ihre Wachsamkeit zu lockern, was dazu führt einige Schüler antworten ohne nachzudenken
● Hallo
● Welt
● Toby
Aber das Ergebnis ist die Ausgabe
● Hallo
● undefiniert
● toby
Dann ist das seltsam, warum sollte es nicht Welt sein? Variablen folgen dem Prinzip der Nähe, sodass js zuerst in der Funktion sucht und dann nach außen sucht, wenn sie nicht gefunden wird und str2 in der Funktion vorhanden ist. Beim Ausführen von console.log (str2) ist str2 jedoch nicht definiert , also undefiniert
lexikalische Analyse
Sie müssen Wissen Sie warum, schauen wir uns also noch ein paar Beispiele an
Beispiel 1
<script> function t(userName) { console.log(userName);//这里输出什么? function userName() { console.log('tom'); } } t('toby'); </script>
Was ist das Ausgabeergebnis? Dieses Beispiel scheint sich vom obigen zu unterscheiden. Es fühlt sich an, als würde man in die Mathematik der High School zurückkehren und verwirrt sein, wenn sich der Fragetyp ändert. Zu diesem Zeitpunkt denken einige Schüler vielleicht, dass es Toby ist, aber die tatsächliche Ausgabe ist
function userName() { console.log('tom'); }
Warum ist es eine Funktion? Tatsächlich kann diese Art von Umfangsproblem durch einen „Satz von Formeln“ erreicht werden. Diese Formel ist die lexikalische Analyse in JS, die durchgeführt werden muss, bevor die Funktion in JS ausgeführt wird. Die erste Aufgabe ist die lexikalische Analyse Was genau ist erforderlich? Parameter analysieren, Variablendeklarationen analysieren, Funktionsdeklarationen analysieren, dann verwenden wir diese Frage, um die Formel
bei der Ausführung anzuwenden t('toby') , startet zwei Phasen, eine ist die Analysephase, Nach der Analyse geht es in die Ausführungsphase.
Analysephase:
● Sobald die Funktion ausgeführt wird, wird ein aktives Objekt generiert (im Folgenden als „Aktives Objekt“ bezeichnet). Als AO-Objekt) befinden sich alle Variablen, die in einem Funktionsbereich gefunden werden können, auf AO. Zu diesem Zeitpunkt wird der Code wie folgt ausgedrückt: t.AO = {}
● Analyseparameter: Parameter empfangen, mit The Der Parametername ist ein Attribut und der Parameterwert ist ein Attributwert. Da keine Parameter vorhanden sind, wird das Analyseergebnis im Code ausgedrückt: t.AO = {userName : toby}
● Analyse der var-Anweisung: Es gibt Keine var-Anweisung in der t-Funktion Diese Funktion, da die Funktion auch eine Art Variable im JS-Feld ist, wird also im Code ausgedrückt: t.AO = { userName : function userName() {console.log('tom');}}
Ausführungsphase:Wenn t('toby') ausgeführt wird und console.log(userName) ausgeführt wird, wird t.AO.userName aufgerufen, sodass das endgültige Ausgabeergebnis lautet function userName() {console.log('tom') ;}
Beispiel 2Was ist dann die Ausgabe hier? Das scheint anders zu sein aus dem obigen Beispiel, und ich bin wieder verwirrt: „Haben Sie keine Angst vor Ärger und befolgen Sie die Formel entschlossen und gehen Sie den Prozess noch einmal durch (das obige Beispiel ist detaillierter geschrieben, die folgende Analyse ist einfach geschrieben)
<script> function t(userName) { console.log(userName);//这里输出什么? var userName = function () { console.log('tom'); } } t('toby'); </script>
Vor der Analyse müssen Sie zunächst zwei Konzepte verstehen, eines heißt Funktionsanweisung und ein Funktionsausdruck heißt
Analysephase://这个叫函数声明 function userName() { console.log('tom'); } //这个叫函数表达式 var userName = function () { console.log('tom'); }
● AO-Objekt erstellen, t. AO = {}
● Analyseparameter: t.AO = {userName : toby}
● 分析var声明: 在AO上,形成一个属性,以var的变量名为属性名,值为undefined,(因为是先分析,后执行,这只是词法分析阶段,并不是执行阶段,分析阶段值都是undefined,如果执行阶段有赋值操作,那值会按照正常赋值改变),也就是说代码应该表示为:t.AO = {userName : undefined},但是还有另外一个原则,那就是如果AO有已经有同名属性,则不影响(也就是什么事都不做),由于分析参数时,AO上已经有userName这个属性了,所以按照这个原则,此时什么事都不做,也就是说,此时按照分析参数时的结果t.AO = {userName : toby}
● 分析函数声明: 此时没有函数声明,略过
执行阶段:
调用t.AO.userName,所以,最后的输出结果是toby
例子3
<script> t(); t2(); function t() { console.log('toby');//这里会输出什么? } var t2 = function () { console.log('hello toby');//这里会输出什么? }; </script>
那么我们再来看一个例子,这下彻底回到高中时代,做了两个例子好像感觉掌握了,结果考试你给来看这个?
答案是,t()输出为toby,t2()则会报错.这又是为什么?
● t()可以调用是因为在词法分析的过程,就已经完成了t函数的分析,所以可以调用
● t2()不能调用是因为在词法分析的阶段,分析到有一个t2声明,在AO上只是形成了一个属性,但是值为undefined
例子4
<script> function t(userName) { console.log(userName);//这里输出什么? function userName() { console.log(userName);//这里输出什么? } userName(); } t('toby'); </script>
函数里面套函数,这次竟然又和前面不一样了...这次我不说答案了,直接先套公式走一波
t('toby')的分析和执行阶段
分析阶段:
● 创建AO对象,t.AO = {}
● 分析参数: t.AO = {userName : toby}
● 分析var声明: 有同名属性,不做任何事,还是t.AO = {userName : toby}
● 分析函数声明: 有同名属性,覆盖: t.AO = {userName : function userName() {console.log(userName);}}
执行阶段: t.AO.userName 输出为function userName() {console.log(userName);}}
userName()的分析和执行阶段
这里也要搞清楚两个概念
//执行userName()分析的是 function () { console.log(userName); }; //而不是 var userName = function () { console.log(userName); };
分析阶段:
● 创建AO对象,userName.AO = {}
● 分析参数: 无,略过
● 分析var声明: 无,略过
● 分析函数声明: 无,略过
执行阶段: 因为此时userName.AO = {}是个空对象,无法执行userName.AO.userName,所以会向上一层找,所以输出t.AO.userName的结果,也就是function userName() {console.log(userName);}}
例子5
<script> function t(userName) { console.log(userName);//这里输出什么? var userName = function () { console.log(userName);//这里输出什么? } userName(); } t('toby'); </script>
好吧,我保证这个是最后一道...这个输出结果是什么呢?我们只要坚定公式没问题,就一定能得出结果,那么再套公式走一波
t('toby')的分析和执行阶段
分析阶段:
● 创建AO对象,t.AO = {}
● 分析参数: t.AO = {userName : toby}
● 分析var声明: 有同名属性,不做任何事,还是t.AO = {userName : toby}
● 分析函数声明: 无,略过
执行阶段: 执行console.log(userName);时调用t.AO.userName 输出为toby,执行完后,代码继续往下执行,那么就到了进行var的赋值操作(var的分析和执行的区别看例子2中我有解释),此时t.AO = {userName : function() {console.log(userName);}},代码继续往下执行,接着就执行到了userName()
userName()的分析和执行阶段
分析阶段:
● 创建AO对象,userName.AO = {}
● 分析参数: 无,略过
● 分析var声明: 无,略过
● 分析函数声明: 无,略过
执行阶段: 按照例子4我们知道userName.AO是个空对象,所以会往上调用t.AO.userName,所以输出为:function () {console.log(userName);}
总结
JavaScript作用域会先在自己的AO上找,找不到就到父函数的AO上找,再找不到再找上一层的AO,直到找到window.这样就形成一条链,这条AO链就是JavaScript中的作用域链.