前言
任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围。JS中的作用域、闭包、this机制和原型往往是最难理解的概念之一。笔者将通过几篇文章和大家谈谈自己的理解,希望对大家的学习有一些帮助。如果有什么理解偏差的地方,希望大家可以评论指出,相互学习。
有过一定编程经验的同学,一定不会对作用域感到陌生,在C/C++/Java中等语言中,作用域从来没有JavaScript中的作用域那样令人困惑以致于成为一个大多数JS开发者都难以跨过的门槛。
作用域形成机制
JS中存在的三种作用域类型:全局作用域,函数作用域和ES6中新加入的块级作用域。
var a = 1; function foo() { var b = 2; console.log(a); // 1 console.log(b); // 2 console.log(c); // ReferenceError } function foo1() { var c = 3; console.log(a); // 1 console.log(b); // ReferenceError console.log(c); // 3 } console.log(a); // 1 console.log(b); // ReferenceError console.log(c); // ReferenceError foo(); foo1();
从上面的例子可以看到,每个函数内部形成了属于自己的作用域,函数内部声明的变量仅仅在定义的函数内部才可以访问。全局作用域中可以访问到的有a,foo,foo作用域中可以访问到的有b,foo,a,foo1的作用域中可以访问到的有c,foo,a。因为foo的作用域嵌套在全局作用域之中,当console.log(a);执行的时候,JS在foo的作用域查找不到a,就会到它的上层(这里是foo的上层直接就是全局作用域)查找,发现这里声明了一个a,将它的值打印了出来。这种从里到外的查找就是根据作用域链查找。foo1和foo的作用域没有嵌套关系,所以相互隔离。
如果函数中使用了未声明的变量怎么办?
function foo() { a = 2; } foo(); console.log(a); // 2
JS引擎在foo中查找不到a的声明,便会到它的上层(这里是全局作用域中)查找,这个时候还是没有查找到a的声明,在非严格模式下,JS引擎会在全局中自动声明一个a,这个时候,未经声明的变量a实际上泄漏到了全局作用域中。
只有使用未声明的变量才会出现变量泄漏的问题么,其实,不仅仅这种写法会出现,更常见的也会出现在for循环和if代码块中也会出现。
for(var i=1;i<10;i++) { console.log(i); } console.log(i); // 10, 这里的i泄漏到了全局作用域中 if(true) { var a = 2; } console.log(a); // 2, 这里的a也泄漏到了全局变量之中
如果你学习过C语言系列的语法,往往很容易感到困惑,if和for居然没有作用域,这真是太奇怪了。这一切的问题的根源,都是由于ES6之前没有块级作用域导致的。所以可想而知,if包裹的代码块,同样里面的声明也是暴露出来的~
一切问题的解决直到ES6中引入了let和const得以完美的解决。使用let和const,将可以使用块级作用域,使得声明变量泄漏的问题得以解决。
for(let i=1;i<10;i++) { console.log(i); } console.log(i); // ReferenceError if(true) { let a = 2; } console.log(a); // ReferenceError
声明提升机制
对于在JS中声明的不论是变量还是函数,基本上都会存在着变量声明提升的行为,将变量的声明提升到所在作用域的顶端。ES6中的let和const不会,在未声明之前都不可以使用。
看看下面的代码
console.log(a); // undefined console.log(b); // undefined console.log(foo); // Function console.log(foo2); // ReferenceError function foo () { console.log('声明提升了哈'); } var a = 1; var b = function foo2() { console.log('不同的函数声明方式提升的结果也不一样哦'); };
JS 引擎解释这段代码之前首先对代码中所有的变量进行了声明的提升,函数声明的提升的优先级是高于普通变量的,函数声明会整个提升到所在作用域的顶端(但是以函数表达式方式声明的函数不会),代码实际上是下面这个样子:
function foo () { console.log('声明提升了哈'); } var a; var b; var foo2; console.log(a); console.log(b); console.log(foo); console.log(foo2); b = function foo2 () { console.log('不同的函数声明方式提升的结果也不一样哦'); }
静态作用域机制(词法作用域)
关于JS中的作用域,需要明确的一点就是,JS中只存在静态作用域(词法作用域)。静态作用域是什么意思呢?意思就是它的作用域在你写下代码的时候就已经确定了,和函数的调用顺序无关,了解这一点。就可以对一些常见的现象进行解释。
var a = 2; function foo() { console.log(a); } var obj = { a: 3, foo: foo } obj.foo(); // 2
foo中的a在代码写完时就确认了,指向了全局作用域中的a,一旦确定就无法更改了。同理,下面的代码
function foo() { console.log(b); // ReferenceError } function foo1 () { var b = 1; foo(); } foo1();
这里,JS引擎在全局作用域中查找不到b,所以会抛出一个异常。所以可以明确的道理是,foo的作用域和foo1的作用域仍然是相互独立的,不会因为调用时候的顺序而更改作用域的嵌套顺序,静态作用域在代码书写时就已经确定无法更改了,明白这一点在分析JS代码的时候尤为重要。
坑外话
变量的遮蔽效应
在函数中定义的变量会遮蔽上层作用域中同名的变量,两个变量互不影响。
var a = 1; function foo() { var a = 2; console.log(a); // 2 } console.log(a); // 1
Try-Catch 中的块级作用域
try-catch的catch中会创建一个块级作用域,该作用域内变量的表现同样遵守变量的声明提升规则。
try { throw undefined; }catch(e) { a = 1; console.log(e); // undefined } console.log(a); // 1, 变量提升规则 console.log(e); // ReferenceError,catch的块作用域中定义的变量
隐式声明
以参数形式传入的变量在函数内部实际上存在的隐式的声明,使用时不算作未声明的变量。
function foo(a) { a = 1; console.log(a); } foo(); // 1 console.log(a); // ReferenceError
本来想一篇文章写完作用域和闭包的,想例子实在是累,就拆作两篇吧,逃~
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
js作用域,js运行机制
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新动态
- 《庄心妍 实力唱将 发烧音乐精选集》[WAV+CUE][380MB]
- [音展纪念碟]2006年《TAA台湾第十六届国际HI-ENDHI-FI音响展》2cd[WAV]
- 中国音乐地图之听见西藏山歌牧歌酒歌2020[WAV分轨]
- 王宏伟2017-永远的红飘带[太平洋影音][WAV+CUE]
- 费翔.1997-NOW现在【第一中国】【WAV+CUE】
- 新格合唱团.1981-我唱你和2辑(滚石新格民歌系列)【新格】【WAV+CUE】
- 陈柏宇.2011-QUINQUENNIUM【SONY】【WAV+CUE】
- 雨果唱片-《金唛系列-蔷薇依韵琼瑶》WAV
- 陈百强《凝望(2012华纳LPCD45限量版)[DMI]》[WAV整轨]
- 模拟之声慢刻CD《徐小凤45周年》[德国母带][低速原抓WAV+CUE]
- 《庄心妍 实力唱将 发烧音乐精选集》[WAV+CUE][380MB]
- 《王菲 单曲合集》[FlAC/分轨][520MB]
- 《费玉清 原味再现 水长流》[WAV+CUE][430MB]
- 群星.1992-畅销榜老歌金曲10CD【风格】【WAV+CUE】
- 孙悦.2024-时光音乐会【金蜂】【WAV+CUE】