一、预编译
- 如果变量未经声明就赋值,此变量为全局对象所有。 a = 10; --> window.a = 10;
- 一切声明的全局变量,全部是window的属性 .var b = 243; --> window.b = 243;
- 预编译发生在函数执行的前一刻
四部曲:
- 先创建AO对象
- 找形参和变量声明,将变量和形参作为AO属性名,值为undefined
- 实参形参统一
- 函数体中找函数声明,值赋为函数体
eg
function fn(a) {
console.log(a); //function a () {}
console.log(b);// undefined
var a = 123;
console.log(a); //123
function a() {}
console.log(a); //123
var b = function () {}
console.log(b); //function () {}
function d() {}
}
fn(1);
//预编译过程
// 1. 创建AO对象
// 2. AO{
// a : undefined
// b : undefined
// }
// 3. AO{
// a : 1
// b : undefined
// }
// 4.AO{
// a : function a () {}
// b : undefined
// d : function d () {}
//之后开始执行函数
做一道题,先找GO(全局的) , 再找AO(自己的)
二、作用域
- 执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象,函数执行就会产生执行期上下文(独一无二的),执行完一次会销毁一次。
- [[scope]]:存储作用域执行期上下文的集合。
三、作用域链
- [[scope]]中所存储法人执行期上下文对象的集合,这个集合呈链式连接,我们把这种链式连接叫做作用域链。作用域链先将自己的AO放在第0位,然后才是GO。
- 查找变量:在哪个函数里面查找变量,就在这个函数的作用域链的顶端依次向下查找。
举个栗子
function a(){
function b(){
var b = 234;
}
var a = 123;
b();
}
var glob = 100;
a();
刚开始的时候a被定义
此时a要被执行
b在开始时就在a的AO中
b在执行时会产生一个属于自己的AO,放在作用域链最顶端 0位。
四、闭包初识
- 当内部函数被保存到外部时,将会生成闭包
- 闭包会导致原有作用域链不释放,造成内存泄漏。
闭包的作用
- 实现共有变量,eg:累加器
- 可以做缓存(存储结构)
- 可以实现封装,属性私有化
- 模块开发,防止污染全局变量
function a() {
function b() {
var bbb = 234;
document.write(aaa);
}
var aaa = 124;
return b;//形成闭包,执行之后销毁a的 AO,但是b的没有被销毁
}
var glob = 100;
var demo = a();//此时存的是b
demo();//124
首先当a定义
a执行完之后,把b存到外部了,a的AO被销毁,但是b还存着A的AO
此时执行demo也就是执行b,找第0位,自己的AO中没有aaa,找第一位,也就是之前a的AO,其中的aaa = 124,访问这个aaa。
1.累加器
function test() {
var num = 100;
function a (){
num ++;
console.log(num);
}
function b () {
num --;
console.log(num);
}
return [a,b];//a,b都和test产生闭包,一对二的关系
}
var myArr = test();
myArr[0]();//101
myArr[1]();//100,在前一个AO的基础上减,因为共用一个test产生的AO
具体讲解如下
2.缓存
function eater() {
var food = "";//作为存储结构来用
var obj = {
eat : function () {
console.log("I am eating " + food );
food = "";
},
push : function (myFood) {
food = myFood;
}
}
return obj;
}
var eater1 = eater();
eater1.push('banana');
eater1.eat();//I am eating banana
五、立即执行函数
执行完就被释放,其余和函数一样
基本结构
1.(function (){
中间写代码
}()) //建议使用第一种
2.(function (){
中间写代码
})()
eg
(function abc (){
var a = 123;
var b = 234;
console.log(a + b); //357
}())
//执行一次之后访问abc会报错,被销毁了
只有表达式才能被执行
function test(){
var a = 123;
}() //这种不能被执行,这个叫函数声明
能被执行符合执行的表达式的函数名会被自动忽略
var test = function (){
console.log('a');
}(); //可以执行,再次访问test,返回undefined
立即执行函数举例
var num = (function (a,b) {
var d = a + b;
return d;//3
}(1,2));
下次将深层次讲解闭包和对象