1 作用域
什么是作用域:作用域分为全局作用域和函数作用域。全局作用域可以理解为是全局对象(window对象,GO对象),而函数作用域可以理解为是一个函数内部的对象(AO对象)。
全局作用域:所有在script标签内的语句都处在全局作用域中;
页面打开时创建GO对象,关闭时销毁;
定义在全局作用域中的变量,变量名是GO对象的属性名,变量值是属性值。
函数作用域:所有在函数体内部的语句的处在函数作用域中;
函数执行时创建AO对象,执行完毕销毁AO对象;
函数作用域中的变量是AO对象的属性名,变量的值是AO对象的属性值;
下一次使用函数时会创建新的AO对象。
1.1语法分析
Js解释引擎会先扫描所有的js代码,查看代码有没有低级的语法错误,如果存在语法错误,则整个程序就不会执行,如果没有语法错误,则进入预解析(编译)阶段
1.2 预编译
全局对象GO
1,创建AO对象 ==> Activation Object(活动对象,作用域,其实叫执行期上下文)
2,找到形参和变量,把形参和变量作为AO对象的属性名,值是undefined
3,实参把值赋给形参
4,在函数中找到函数声明,把函数名作为AO对象的属性名,值是函数体
function myTest(a, b) {
/*
第一步,AO{ }
第二步
AO{
a:undefined;
b:undefined;
c:undefined;
}
第三步
AO{
a:10;
b:20;
c:undefined;
}
第四步
AO{
a:function() {
console.log(100)
};
b:20;
c:undefined;
}
*/
console.log('a1', a); //f a(){}
console.log('b1', b); //20
console.log('c1', c); //undefined
var c = 30;
b = 200;
function a() {
};
console.log('a2', a); //f a(){}
console.log('b2', b); //200
console.log('c2', c); //30
};
let result = myTest(10, 20);
console.log(result);
预编译后就开始一行一行执行代码,该改值的改值。要注意的一点是,这里的c是用var声明的,用let和const声明不会提升,会报错。
2 作用域链
1. 变量查询规则
当遇见使用一个变量时,JS引擎会从其所在的作用域依次向外层查找,查找会在找到第一个匹配的标识符的时候停止。(有同名的变量会发生“遮蔽效应”)
let a = 1000;
function myTest() {
let b = 20;
outer()
function outer() {
let c = 30;
b = 200;
console.log(a);//1000
console.log(b);//200
inner()
function inner(){
a = 1;
console.log(a);//1
console.log(c);//30
}
}
}
let result = myTest();
console.log(result);
2. 作用域链原理理解:
scope翻译过来就是范围的意思。
[[scope]]中所存储的就是执行期上下文对象的集合,这个几个呈链式连接,我们把这种链式链接叫做作用域链。
比方说上述代码中
myTest
outer
inner
作用域链 = 函数执行时的AO对象 + 函数创建时的环境。
变量查找规则:沿着当前函数作用域链作用域链顶端,自上而下寻找变量。
3 闭包
闭包是什么:闭包是指那些引用另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。把一个函数从它定义的那个作用域,挪走,运行。这个函数能够记忆住定义时的那个作用域。不管函数走到哪里,定义时的作用域就带到了哪里。这就是闭包。
上代码
function myTest() {
let count = 0;
return function inner() {
console.log(count)
}
}
let count = 10;
let inn = myTest();
let result = inn()//0
我们都知道,inner是定义在myTest内,无法通过inner()直接在全局作用域中直接调用的;
但这里把inner函数 return出来,执行myTest等于返回一个inner函数。
function sum(x,y) {
return function innerSum(x) {
return x + y
}
}
let test = sum(3,7);
test(1)//8,3被8代替了
每次调用一个函数,都会产生新的闭包.新的闭包知道是,语句全新,所处环境也是全新的。
function myTest() {
let count = 0;
return function inner() {
count++;
return count
}
}
let count = 10;
let inn1 = myTest();
let inn2 = myTest();
inn1();//1
inn1();//2
inn1();//3
inn2();//1
闭包的作用
1,函数累加器
function outer(){
var count = 0;
function inner(){
count++;
console.log(count);
}
return inner;
}
var inn1 = outer();
inn1(); //1
inn1(); //2
2,可做缓存
function test(){
var num = 100;
function aa(){
num ++;
console.log(num);
}
function bb(){
num --;
console.log(num)
}
return [aa,bb]
}
var myArr = test()
myArr[0]()//执行num++,101
myArr[1]() //执行num--,100