Home > Article > Web Front-end > Deep understanding of JavaScript scopes
Introduction
JavaScript is full stack Language, especially in 2016, I often hear that JavaScript is going to dominate the world. There are even rumors that you can find a job if you know Vue.js in 2016, just like you can find a job if you know TableView on iOS back then. (tableView is quite Based on Android's ListView, but now they basically use RecyclerView)
The popular front-end technologies in 2016 are basically related to JavaScript, such as the mobile cross-platform React Native produced by Facebook and Alibaba's Weex, hot repair technology JSPath, and Node.js on the backend (a technology stack that I like very much). I went to gibhub last night to check it out. The number of stars for Vue has exceeded that of jQuery. Although the number of stars does not prove anything, at least we have already I can see that the front-end thinking has changed from the previous document operation to data-driven development (if you are interested, I can combine Android, iOS, and Vue later to demonstrate this thinking change with a small demo). Some companies have even begun to try to use Hungry Element produced by this company to replace EasyUI (students who have done back-end should know that EasyUI is really AV quality...)
JS technology emerges in endlessly, there was a very popular article before, learning JS in 2016 What kind of experience it was, it scared the shit out of many people in an instant. Everyone focused on frameworks and new technologies, but native JS was left out in the cold, so I wanted to share some basic JS issues with you. Let’s communicate together (I hope everyone will take me to fly, but don’t leave me flying on Malaysia Airlines...)
## Scope in JavaScript
<script> var str1 = "hello"; var str2 = "world"; function t1() { console.log(str1); console.log(str2); var str2 = "toby"; console.log(str2); } //这里会输出什么? t1(); </script>This is a very simple JS scope question, but the more you emphasize simplicity These two words make it easier for people to relax their vigilance, which leads some students to answer without thinking ● hello● world● tobyBut the result is output● hello● undefined● toby Then this is strange, why is there undefined? It shouldn’t be world? First of all, we need to understand that the search for variables will follow the principle of proximity, so js will first search in the function, and then look outside if it cannot find it. There is str2 in the function, but when running to console.log (str2) str2 is not defined, so undefined
#lexical analysis
To know what is happening, you must know why, so let’s look at a few more examples
<script>
function t(userName) {
console.log(userName);//这里输出什么?
function userName() {
console.log('tom');
}
}
t('toby');
</script>
What is the output result? This example seems to be the same as the above It’s different. It’s like going back to high school mathematics and feeling confused when the question type changes. At this time, some students may think it’s toby, but the actual output is
function userName() { console.log('tom'); }
Why is it function? In fact, this function Domain issues can all be derived through a "set of formulas". This formula is lexical analysis in JS. One of the tasks that must be done before the function in JS is executed is lexical analysis. So what exactly is required? Analysis Parameters, analysis of variable declarations, analysis of function declarations, then we will use this question to apply the formula
When executing t('toby'), two stages will begin. One is the analysis stage. After the analysis, Let’s go to the execution phase
Analysis phase:
● The moment the function runs, an Active Object object (hereinafter referred to as the AO object) will be generated. All variables that can be found within the scope of a function are On AO, the code at this time is expressed as: t.AO = {}
● Analysis parameters: Receive parameters, use the parameter name as the attribute, and the parameter value as the attribute value. Because there are no parameters, the analysis result uses the code Represented as: t.AO = {userName : toby}
● Analysis of var declaration: There is no var declaration in the t function, skip
● Analysis of function declaration: This function declaration has a characteristic, If there is an attribute on AO with the same name as the function name, it will be overwritten by this function. Because the function is also a type of variable in the JS field, it is expressed in code as: t.AO = { userName : function userName() {console .log('tom');}}
Execution phase:
When executing t('toby'), when console.log(userName) is executed, t is called. AO.userName, so the final output result is function userName() {console.log('tom');}
Example 2<script>
function t(userName) {
console.log(userName);//这里输出什么?
var userName = function () {
console.log('tom');
}
}
t('toby');
</script>
Then here What is the output? This seems to be different from the above example, and it has fallen into confusion again? Don’t be afraid of trouble and resolutely follow the process according to the formula (the above example is written in more detail, the following analysis is simple Write)
Before analysis, you must first understand two concepts, one is called function declaration and the other is called function expression
//这个叫函数声明 function userName() { console.log('tom'); } //这个叫函数表达式 var userName = function () { console.log('tom'); }
Analysis stage:
● Create AO object, t.AO = {}
● Analysis parameters: 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 userName() {console.log(userName);}}},代码继续往下执行,接着就执行到了userName()
userName()的分析和执行阶段
分析阶段:
● 创建AO对象,userName.AO = {}
● 分析参数: 无,略过
● 分析var声明: 无,略过
● 分析函数声明: 无,略过
执行阶段: 按照例子4我们知道userName.AO是个空对象,所以会往上调用t.AO.userName,所以输出为:function userName() {console.log(userName);}}}
总结
JavaScript作用域会先在自己的AO上找,找不到就到父函数的AO上找,再找不到再找上一层的AO,直到找到window.这样就形成一条链,这条AO链就是JavaScript中的作用域链.JavaScript中有两条很重要的链,一条是作用域链,一条是原型链,