《深入理解JavaScript作用域.pdf》由会员分享,可在线阅读,更多相关《深入理解JavaScript作用域.pdf(12页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、深入理解JavaScript作用域avaScript是门全栈性的语言,尤其是在2016年,经常听到JavaScript要一统天下的梗甚至有流言说16年会个VueJs就能找到工作和当年iOS会个TableView就能找工作一样(tableView就相当于Android的ListView,不过现在基本都用RecyclerView了)2016年前端的热门技术基本都和丿avaScript有关比如移动端跨平台的Facebook出品的ReactNative和阿里的Weex热修复技术丿SPath,以及后端的NodeJs(本宝宝非常喜欢的一门技术栈)昨晚去gibhub看了下,Vue的star数最已经超过了jQ
2、uery虽然star数最并不能证明些什么但是至少我们已经看到前端思想已经从之前的document操作到了数据驱动开发的转变(有兴趣的话我可以之后结合Android、iOS、Vue,用一个小demo演示一下这个思想转变)有些公司甚至开始尝试用饿了么出品的Element来替代EasyUI(做过后端的同学应该都知道EasyUI真的是AV画质)JS技术层出不究之前就有篇很火的文章,2016年学丿S是种什么样的体验,瞬间吓尿了不少人大家都把注意力放到了框架和新技术上原生的JS反而遭到了冷落所以想通过几个基础性的JS问题和大家起交流(更希望大家带我飞但是别把我丢到马航上飞)JavaScript中的作用域下
3、面个简单的问题勹 上var strl=hello;2 var str2=world;3 4 function t1()5 console.log(strl);6 console.log(str2);7 var str2=toby;8 console.log(str2);9 10/这里会输出什么?11 tl();12 13 14 15 16 这是一个很简单的丿S作用域问题但是你越是强调简单这两个字就越容易使人放松警惕所以导致有些同学不假思索的回答输出 hello world toby 但是结果是输出 hello undefined toby 那么这就奇怪了,为什么会有undefined呢不是应该
4、是world吗?首先我们要明臼变量的寻找会遵循就近原则,所以js会先在函数中找找不到才会向外找而函数内有str2,但是运行到console.log(str2)时str2未定义所以就出现了undefined 词法分析知其然还必须其所以然那么我们再来看几个例子例子1 l function t(userName)2 console.log();这里输出什么?3 4 5 6 function userName()console.log(tom);t(toby);7 8 9 10 输出的结果是什么,这个例子好像和上面不一样,有种回到高中数学,题型一变就漕逼的感觉这个时候可能有些同学会觉得是toby,但是
5、实际输出是lfunction userName()23 console.log(tom);为什么是function呢?其实这种作用域的问题都是可以通过“套公式来得出,这个公式就是JS中的词法分析,丿S中函数执行前必须要做的项工作就是词法分析那么究竟要什么什么呢?分析参数分析变量声明,分析函数声明那么我们就拿这道题来套下公式执行t(toby)的时候会开始两个阶段个是分析阶段分析完就到执行阶段分析阶段函数运行的瞬间会生成个ActiveObject对象(以下简称AO对象),个函数作用域内能找到的所有变呈,都在AO上,此时用代码表示为t.AO=分析参数:接收参数以参数名为属性参数值为属性值因为没有参数
6、因此分析结果用代码表示为:t.AO=userName:toby 分析var声明t函数内没有var声明略过分析函数声明这个函数声明有个特点AO上如果有与函数名同名的属性,则会被此函数覆盖,因为函数在JS领域也是变星的一种类型因此用代码表示为:t.AO=userName:function userName()console.log(tom);执行阶段执行t(toby)的时候当执行到console.log(userName)时就调用t.AO.userName所以最后的输出结果是functionuserName()console.log(tom);例子2 1 function t(userName)2
7、 console.log(userName);这里输出什么?3 4 5 6 var userName=function()console.log(tom);t(toby);7 8 9 10 那这里的输出又是什么呢?这个好像又和上面的例子不一样又再次陷入惜逼状态?别怕麻烦,坚定的按照公式再走一次流程(上面的的例子写得比较详细下面的分析就简单写)分析之前首先要弄明白两个概念,一个叫函数声明一个叫函数表达式/这个叫函数户明1 function userName()23 console.log(tom);4 这个叫函数表达式Svar userName=function()67 console.log(
8、tom);8 9 分析阶段创建AO对象t.AO=分析参数t.AO=userName:toby 分析var声明在AO上,形成个属性,以var的变量名为属性名值为undefined,(因为是先分析后执行,这只是词法分析阶段并不是执行阶段分析阶段值都是undefined如果执行阶段有赋值操作那值会按照正常赋值改变),也就是说代码应该表示为:t.AO=userName:undefined,但是还有另外一个原则那就是如果AO有已经有同名属性则不影响(也就是什么事都不做),由于分析参数时,AO上已经有userName这个属性了所以按照这个原则此时什么事都不做,也就是说此时按照分析参数时的结果t.AO=us
9、erName:toby 分析函数声明此时没有函数声明略过执行阶段调用t.AO.userName,所以最后的输出结果是toby例子3 1 t.();2 t2();3 4 5 function t()console.log(toby);/这里会输出什么?6 7 var t2=function()console.log(hello toby);这里会输出什么?8;9 10 11 12 那么我们再来看一个例子,这下彻底回到高中时代做了两个例子好像感觉掌握了,结果考试你给来看这个?答案是tO输出为toby,t2()则会报错这又是为什么?t()可以调用是因为在词法分析的过程就已经完成了t函数的分析,所以可
10、以调用 t2()不能调用是因为在词法分析的阶段分析到有个t2声明在AO上只是形成了个属性但是值为undefined例子4 L function t(userName)2 3 4 5 console.log(userName);这里输出什么?function userName()console.log(userName);/这里输出什么?userName();6 t(toby);7 8 9 10 函数里面套函数这次竟然又和前面不样了这次我不说答案了直接先套公式走波t(toby)的分析和执行阶段分析阶段创建AO对象,t.AO=分析参数t.AO=userName:toby 分析var声明有同名属性,
11、不做任何事还是t.AO=userName:toby 分析函数声明有同名属性覆盖:t.AO=userName:function userName()console.log(userName);执行阶段t.AO.userName输出为functionuserName()console.log(userName);userName()的分析和执行阶段这里也要搞清楚两个概念/执行userName()分析的是function()2 console.log(userName);3 ;4/而不是Svar userN ame=function().67 console.log(userName);8 9 分析
12、阶段创建AO对象,userName.AO=分析参数无略过分析var声明无略过分析函数声明无略过执行阶段因为此时userName.AO=是个空对象无法执行userName.AO.userName,所以会向上层找所以输出t.AO.userName的结果,也就是functionuserName()console.log(userName);例子5 1 functiont()2 3 4 5 console.log(userName);这里输出什么?var userName=function()console.log(userName);这里输出什么?userName();t(toby);b 7 8 9
13、0 1 好吧我保证这个是最后一道这个输出结果是什么呢?我们只要坚定公式没问题就一定能得出结果那么再套公式走一波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()conso
14、le.log(userName);,代码继续往下执行接着就执行到了userName()userName()的分析和执行阶段分析阶段创建AO对象,userName.AO=分析参数:无略过分析var声明无略过分析函数声明:无略过执行阶段按照例子4我们知道userName.AO是个空对象所以会往上调用t.AO.userName所以输出为:functionuserName()console.log(userName);总结JavaScript作用域会先在自己的AO上找找不到就到父函数的AO上找再找不到再找上一层的AO直到找到window这样就形成一条链这条AO链就是丿avaScript中的作用域链归vaScript中有两条很重要的链一条是作用域链一条是原型链