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。
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}
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开始查 一直++
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
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
}())
2
3
4
5
也可以有参数
(function (a, b, c) {
consloe.log(a + b + c * 2);
//输出9
}(1, 2, 3))
2
3
4
也可以有返回值
var num = (function (a, b, c) {
var d = a + b + c *2-2;
return d;
}(1, 2, 3))
//要接收返回值,不管里面多复杂
//可以用变量来接收
2
3
4
5
6
# 立即执行函数原理
# 两种写法
(function(){}()); //w3c建议这种
(function(){})();
2
只有表达式才能被执行符号执行
function test() {
var a = 123;
}
test();
2
3
4
总结
test()也叫表达式,之所以test()语句能执行函数,因为test代表一个引用(函数的名字)。函数的名字加上()执行符就可以执行。
var test = function() {
consloe.log('a');
}();
//此条语句也能被执行,因为它叫函数表达式
2
3
4
一个表达式被执行,他就会忽略它自己的名字。
在控制台打印test会出现undefined,因为他已经被()执行了,是一次性的。
(function () {
console.log('a');
}();
2
3
把函数声明用括号包起来就可以变成表达式,故有(function(){})();也可以将括号写在里面。
(function () {
console.log('a');
}());
2
3
解析
因为外层的括号是数学运算符 所以先算外层的括号,从左到右从上到下,最后执行函数该函数
# 题
var f =(
function f() {
return "1";
}
function g() {
return 2;
}
)();
console.log(typeof(f)); //number
// 有逗号的返回逗号后面的。
2
3
4
5
6
7
8
9
10