一、作用域
1、什么是作用域(Scope)
作用域就是变量可以被调用生效的范围,js的作用域是定义时候产生的
2、JS的作用域的分类(含ES6)
JS作用域可以分为三大类:全局作用域 、局部作用域(函数作用域),块作用域
(一)全局作用域:
直接编写在 script 标签之中的JS代码或者是一个单独的 JS 文件中的,都是全局作用域。
全局作用域在页面打开时创建,页面关闭时销毁;
在全局作用域中有一个全局对象 window(代表的是一个浏览器的窗口,由浏览器创建),在全局作用域中,所有创建的变量都会作为 window 对象的属性保存,可以直接使用。
var a;
let b;
(二)局部作用域(函数作用域):
在函数内部就是局部作用域,这个代码的名字只在函数的内部起作用
调用函数时创建函数作用域,函数执行完毕之后,函数作用域销毁;
每调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的。
function sun(x,y){
return x+y
}
(三)块级作用域
块作用域由 { } 包括,if 语句和 for 语句里面的 { } 也属于块作用域。
function f1() {//块作用域
let n = 5;
if (true) {//块作用域
let n = 10;
}
console.log(n); // 5
}
二、作用域链
只要是代码,就有一个作用域,函数会开辟一个新的作用域
当在函数作用域中操作一个变量的时候,会先在自身作用域中查找,如果有就直接使用,如果没有就向上级作用域中寻找。依次查找,一直到全局,全局还是没有,显示 is not defined。
根据内部函数可以访问可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为函数作用域链。
作用域链:内部函数访问外部函数的变量,采取的是链式查找的方法来决定取那个结构,这种结构称之为作用域链。
作用域链的原则:就近原则
作用域链采用链式查找的方式,一层一层向上查找,先查找外面的嵌套的函数是否有所需内容,找到就输出相应的结果,依次查找,一直到全局,全局还是没有,显示 is not defined。找到链式结构层次最低的就停止,就近原则.
实例:
下面代码最终输出的结果?
注意:在更长的结构中画图分析太过于麻烦,可以从输出目标console.log(); 位置向外层的结构看,寻找最近的变量。
var a = 1;
function fn1(){
var a=2;
var b='22';
fn2();
function fn2(){
var a =3;
fn3();
function fn3(){
var a=4;
console.log('a= ' + a); //求 a的值
console.log('b= ' + b); //求 b的值
}
}
}
fn1();
最终结果是:
a= 4
b= 22
三、作用域的思考拓展
(一)闭包:
闭包就是运用作用域链将变量传递于内部函数,后使用或者return暴露在内存中
(二)this指向:
this指向是调用时决定的
闭包情况下,this指向是调用时的上下文环境;就是其所在函数的作用域所属对象
<!doctype html>
<html lang="en"><head><meta charset="UTF-8"></head><body></body></html>
<script>
let obj = {
getName: getName
}
function getName () {
setTimeout(function xiaosan() {
console.log(this === obj) // false
}, 0)
}
obj.getName()
</script>
纳尼!!不是obj调用的吗?不是this会指向obj吗?究竟是谁?
别急别急,我们来分析一下,this在xiaosan函数。
但是xiaosan函数作用域环境是什么?xiaosan函数被定时器setTimeout调用,那定时器setTimeout的作用域是什么?哦,是不是恍然大悟,就是window对象