function a() {
       function b() {
            var bbb = 234;
            console.log(aaa);
        //自己的执行期上下文没有 aaa
        //所以忽略了第 0 位(bAO)
        //去第 1 位(aAO)里面找aaa 123
        //所以打印 123
        }
        var aaa = 123;
        return b;
        //b 被返回,b 没有被执行
        // 相当于返回 b 函数
        //return b 只是b 函数引用
        //此刻 a 已经执行完毕
    }
var glob = 100;
var demo = a(); 
demo();//123
//把 a 函数保存到了 demo 变量里
//demo 执行相当于 b函数 也执行
//也就是说 b 函数的值被保存到了外部

//a执行完a会销毁自己的AO
//外部的b不会销毁a的AO。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

此时的 a 执行(doing),造成了a 函数里面的 b 函数定义,b 函数定义保存的是 a 的劳动成果(AO)(永远保留 aAO,可以理解为 bGO) a 函数执行完毕,要销毁作用域链,剪掉 自己的AO,但是 b 函数被保存到了外部。所以就拽着 a 函数的 AO 不放,a 执行完并不影响 b 执行

function a() {
           var num = 100;
           function b() {
                num++;
                console.log(num);
           }
           return b;
    }
    var demo = a();
        demo();     //101
        demo();     //102
        //aAo {num : 102}
1
2
3
4
5
6
7
8
9
10
11
12

b 拿着 a 的劳动成果,被保存到了外部,a 执行完销毁 var demo = a(),b 始终攥着 a 的劳动成果 aAO,a 的 AO 里面存着 num 值100,第一次执行 b,demo(),num++等于100,b 执行完销毁自己的 AO,第二次执行还是 a 的 AO,101,基础上++,因为自己的 AO 里面没有 num。

闭包现象

当内部函数被保存到外部时,将会生成闭包。

闭包危害

闭包会导致原有作用域链不释放,造成内存泄漏(内存占据)

闭包作用

1.实现共有变量

2.可以做缓存

3.可以实现封装,属性私有化

4.模块化开发,防止污染全局变量

# 例子:实现公有变量

实现累加器

function add() {
         var count = 0;
         function demo() {
                count++;
                console.log(count);
        }
        return demo;
        //把 demo 函数返回但未执行
        //add函数执行完毕
}
        var counter = add();
        counter();
        counter();
        counter();
        counter();
        counter();
        counter(); 
//每次调用都会查数,从0开始查 一直++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 可以做缓存

function test() {
        var num = 100;
        function a() {
                num++;
                console.log(num);
         }
        function b() {
                num--;
                console.log(num);
         }
         return [a, b]; 
//将函数a和函数b都返回到数组
}
var myArr = test(); 
//将test 函数里的a函数和 b 函数都赋值给myArr
myArr[0]();       //myArr的第0位 101
myArr[1]();       //myArr的第1位 100
//函数a和函数b执行的话都绑定的test函数的AO
//a函数执行完101销毁自己的AO
//此时绑定的test函数的AO为 101 
//b函数执行也绑定testAO num-- 所得100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 立即执行函数

立即执行函数

功能:针对初始化功能的函数,因为只执行一次,就立即销毁。

特点:函数执行完就释放,从出生到现在只被执行一次

写法:1.先写一个括号(),2.在括号里面写匿名函数 3.写完写一个括号执行

(function () {
        var a = 123;
        var b = 234;
        console.log(a + b); //输出357
}())
1
2
3
4
5

也可以有参数

(function (a, b, c) {
        consloe.log(a + b + c * 2);  
        //输出9
}(1, 2, 3))
1
2
3
4

也可以有返回值

var num = (function (a, b, c) {
       var d = a + b + c *2-2;
       return d;
}(1, 2, 3))
//要接收返回值,不管里面多复杂
//可以用变量来接收
1
2
3
4
5
6

# 立即执行函数原理

# 两种写法

(function(){}());    //w3c建议这种
(function(){})();
1
2

只有表达式才能被执行符号执行

function test() {
       var a = 123;            
}
test();  
1
2
3
4

总结

test()也叫表达式,之所以test()语句能执行函数,因为test代表一个引用(函数的名字)。函数的名字加上()执行符就可以执行。

var test = function() {
        consloe.log('a');
}();            
//此条语句也能被执行,因为它叫函数表达式
1
2
3
4

一个表达式被执行,他就会忽略它自己的名字。

在控制台打印test会出现undefined,因为他已经被()执行了,是一次性的。

(function () {
         console.log('a');
}();
1
2
3

把函数声明用括号包起来就可以变成表达式,故有(function(){})();也可以将括号写在里面。

(function () {
        console.log('a');
}());
1
2
3

解析

因为外层的括号是数学运算符 所以先算外层的括号,从左到右从上到下,最后执行函数该函数

#

var f =(
        function f() {
        return "1";
    }
        function g() {
        return 2;
    }
)();
 console.log(typeof(f));  //number
//  有逗号的返回逗号后面的。
1
2
3
4
5
6
7
8
9
10