持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
js的作用域大致分为:全局作用域、函数作用域(局部作用域)、块级作用域
学习链接:(可以先看一遍哇)
1. JS中的作用域(超详细,看完秒懂)
2. 如何理解javascript的作用域?
3. 阮一峰-let-const-块级作用域
# 块级作用域与函数声明:if内【块级作用域】的是否提升到头部
作用域相关概念及定义
变量起作用的范围,变量在啥地方能用。那么啥地方就是它的作用域。
1.全局作用域(Global Scope)
指:在代码中任何地方都能访问到的对象拥有全局作用域。
一般来说一下几种情形拥有全局作用域:
(1)在函数外面定义的变量拥有全局作用域
(2)所有末定义直接赋值的变量自动声明为拥有全局作用域
(3)所有window对象的属性拥有全局作用域
2. 局部作用域(Local Scope)
指:和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域成为函数作用域。
全局作用域--局部作用域图解
作用域链
functionA(){
vara=1;
functionB(){//在A函数内部,声明了函数B,这就是所谓的函数嵌套。
varb=2;
}
}
函数B在执行的时候,是会引用函数A的作用域的。[ ⬆ 可看上图解 ]
所以,像这种函数作用域的嵌套就组成了所谓的函数作用域链。
当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,
若在全局作用域内部仍找不到该变量,则会抛出异常。
其实作用域链就是JS引擎查询数据的一个链表,后定义的覆盖先定义的,
查询不到定义的数据就往深一层查询,一直到全局作用域为止
但是越往内层延伸,读写速度就会越慢,查找全局变量是最慢的。
所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。
如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。
如何运用作用域链的知识进行性能优化:
例如:内部不同函数内多次使用document.getElementById('xxx')的时候,
可以先定义var doc=document;
1.Javascript在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),从而确定实变量的作用域。
2.Javascript的变量的范围是根据方法块来划分的(也就是说以function的一对大括号{ }来划分)。切记,是function块,而for、while、if块并不是作用域的划分标准。
3.当全局变量跟局部变量重名时,局部变量的范围会覆盖掉全局变量的范围,当离开局部变量的范围后,又重回到全局变量的范围。(若想指定是全局变量可以使用 window.globalVariableName)
3. 块级作用域
块级作用域可通过新增命令 let 和 const 声明,所声明的变量在指定块的作用域外无法被访问。
块级作用域在如下情况被创建:
在一个函数内部
在一个代码块(由一对花括号包裹)内部
let 声明的语法与 var 的语法一致。基本上可以用 let 来代替 var 进行变量声明,但会将变量的作用域限制在当前代码块中。
块级作用域有以下几个特点:
声明变量不会提升到代码块顶部
let/const 声明并不会被提升到当前代码块的顶部,因此你需要手动将 let/const 声明放置到顶部,以便让变量在整个代码块内部可用。
js作用域相关的代码情况及我的理解 【仅供参考啊,有不对的请告诉我,拜托拜托】:
1
var scope='global';
function fn(){
alert(scope);
var scope='local';
alert(scope);
}
fn();
alert(scope);
//结果是undefined , local , global
理解:
scope 两次被声明【var】, 其中fn内(var)声明了scope,形成了一个函数作用域,
不受外部声明的影响,也不影响外部,
又因为使用的是var声明---有变量提升,声明前调用不报错而显示undefined
var scope='global';
function fn(){
alert(scope);
scope='local';
alert(scope);
}
fn();
alert(scope);
//结果是global , local , local
2
var age=250;
function testf(){
var age = 10;//声明,并赋值;
console.log("testf:age="+age);//age是局部变量,因为testf函数内部定义了age。10;
testf1();
}
function testf1(){
console.log("testf1:age="+age);age是全部变量,因为testf1函数内部没有定义age。250;
}
理解:
testf内声明了age,形成一个函数作用域,不受外部声明的影响,也不影响外部重名变量的声明,
关于 testf1函数:在函数外面定义的变量拥有全局作用域 故该函数内的age为声明的全局函数
3
var scope='global';
function fn(scope){
alert(scope);
scope='local';
alert(scope);
}
fn();
alert(scope);
//结果是undefined , local , global
fn函数定义了变量(scope),内部不能再重新赋值,原因如下图所示。
且 所有末定义直接赋值的变量自动声明为拥有全局作用域 故为undefined
局部作用域内声明的变量,不影响也不受外部声明的重名变量的影响
为什么需要块级作用域?
第一种场景,内层变量可能会覆盖外层变量。[如下代码所示]
第二种场景,用来计数的循环变量泄露为全局变量。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
这个我不是很理解,阮一峰所述:
`if`代码块的外部使用外层的`tmp`变量,内部使用内层的`tmp`变量。
但是,函数`f`执行后,输出结果为`undefined`,
原因在于变量提升,导致内层的`tmp`变量覆盖了外层的`tmp`变量
后来我查了一下关于var及块级作用域的,
只有let和const有块级作用域,var没有作用域,
var在块级作用域中声明的变量在全局有效,
而fn()为函数作用域,及fn()内新声明了tmp,提升到函数顶部,所以因为在函数内提前调用而打印出undefined