学习前端也有一段时间了,觉得自己可以与大家分享一些我当初遇到疑惑的东西,希望能给对此问题有疑惑的朋友带来一点帮助。
先来普及一下JS的概念(不要嫌我啰嗦,可能一些朋友开始学习JS是跟着视频和写好的代码学的,应该有一部分对它的结构或者说它的历史还不太了解),JavaScript由三种东西组成,一个叫ECMAScript,一个叫DOM,还有一个叫BOM,我们现在说的JS其实是它的核心——ECMAScript,简称ES。如今市面上的浏览器大部分是运行的ES5,但有一些也支持ES6,某些技术大牛都是用ES6编程然后转ES5,工具是Babel。但我们现在首要学习的还是ES5,只有深入理解了ES5才能做好其他事情。
言归正传,今天我们谈的是ES5里面的作用域链和原型链,当时我学习这一章的时候也是比较害怕的,因为以前学习生物的时候啊,什么DNA链啊生物链啊,就感觉特复杂,对链这个玩意有种“一朝被蛇咬十年怕井绳”的感觉。后来在不断地学习与编码过程中呢,我逐步的理解了这一些东西,也感谢一些前辈们的文献与代码。
说到底作用域链,顾名思义,它是与作用域在一起的,何为作用域,我们知道JS里的function,它是用来声明一个函数的,每一个函数运行的时候会拥有一个自己的执行环境,每个执行环境都能拥有一个位置来存储这个环境里面定义的变量和函数,当这个执行环境的所有代码执行完了之后,该环境被销毁,保存在其中的所有变量和函数定义也被销毁掉了,我们可以把这一个执行环境称为一个作用域。(这里值得一提的是ES5没有块级作用域的概念,只有函数里面的东西运行完会被销毁,不在函数里的东西,比如for(var i=0;i<10,i++)这个i不在函数里,而是在一个全局的循环中,它就是一个全局变量。这些问题一些大公司正在协商解决,ES6里大体上已经优化的很好了)
说完了作用域,我们就可以来讲讲作用域链了,作用域链是单向的。全局window是最大的作用域,全局里声明的函数是次一级的作用域,这样的函数里面可以访问到全局里的各种变量和函数,但在全局中访问不到这个函数里面的函数和变量;这样次一级里面的函数是再次一级,它同样也是可以访问上一级和全局的函数与变量,而上级访问不到这个里面的东西,这样一层一层的递进,就成了一条链子,也就是作用域链;
我们看一串代码:
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title></title> 7 </head> 8 9 <body> 10 <script type="text/javascript"> 11 var idol = "J.J"; 12 13 function writeIdol() { 14 console.log("我的偶像是" + idol); //J.J(可以访问11行全局的idol) 15 idol = "eason"; //修改了11行idol的值 16 function askAnotherIdol() { 17 var anotherIdol = "echo"; 18 console.log("我的偶像是" + idol); //15行“eason” 19 console.log("其他的偶像有" + anotherIdol) //17行“echo” 20 } 21 askAnotherIdol(); 22 console.log("我的偶像是" + idol); //这个时候得到的是15行“eason” 23 console.log("其他的偶像有" + anotherIdol) //得不到了,因为作用域链是单向的 24 } 25 writeIdol(); 26 //执行顺序为:writeIdol函数执行==>输出idol(“J.J”)==>修改idol为"eason"==>执行askAnotherIdol函数 27 //==>在函数内部声明新变量anotherIdol值为"echo",输出全局idol(已修改“eason”)==>输出其他的偶像有“echo” 28 //==>输出全局idol(已修改“eason”)==>输出anotherIdol(anotherIdol is not defined,因为作用域链的单向) 29 </script> 30 </body> 31 32 </html>
作用域链可以通过这个例子来理解,通俗点,大鱼吃小鱼,小鱼吃虾米——大鱼可以吃小鱼,小鱼却吃不了大鱼。我们可以把全局当成虾米,最里面的函数当大鱼就好啦,虽然理解起来有点奇怪,如果没有自己的理解方式,这样套用一下也是可以的嘛。
作者也是第一次写博客,如果写的不太好或者有疑惑的,欢迎大家提出建议和问题,因为要吃饭啦,本篇就先写个我对作用域链的理解吧,原型链在下一篇好好写写。