可参考03——作用域的内容
小例子:
demo执行就是b执行,只是不同名字,a里return b语句并没有执行b函数
b定义时就保存了a的劳动成果,b执行完后回到定义的状态并且销毁了自己的AO(这里是空),不销毁别人的AO,所以第二次执行是102
内存泄漏就是占有内存的意思
函数声明:function test(){} 函数声明没有被执行
函数表达式:函数表达式能被执行,var demo=function(){}() 变成一次性的了,再去控制台查看demo显示为空的demo变量,执行完函数就销毁了 ,
立即执行函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!--
闭包:当内部函数被保存到外部时,将会生成闭包,闭包会导致原有作用域链不释放,造成内存泄露(占用)
闭包的作用:
1:函数累加器
2:可以做缓存(存储结构)
3:可以实现封装,属性私有化
4:模块化开发,防止污染全局变量
-->
<!-- 立即执行函数:定义 此类函数没有声明,在一次执行过后即释放,适合做初始化工作
针对初始化功能的函数,执行完就被销毁掉,不占用空间,它有一般函数的特点,不同的是执行完会被销毁
(function (){}()); W3C建议第一种
(function (){})();
执行函数后,在控制台输入函数名,会显示 ***is not defined
-->
<script>
(function abc(){//可以是匿名函数 function (){}())
var a=123;
var b=234;
console.log(a+b);
}())//后面有个小括号,小括号是执行括号, 执行完就找不到了
</script>
<!-- 括号里也可以写形参 后面的小括号传实参 -->
<script>
(function (a,b,c){
console.log(a+b+c*2);
}(1,2,3))
</script>
<!-- 可以有返回值 -->
<script>
var num=(function (a,b,c){
var d=a+b+c;
return d;
}(1,2,3))
</script>
<!-- *只有表达式才能被执行符号执行
函数声明:function test(){}
表达式:test()
函数表达式:var test=function(){
console.log('a');
}()
可执行表达式被执行后,放弃函数名字,和执行函数一样,执行一次就被放弃了-->
<script>
function test(){
console.log('a');
}//() 这里不可以执行 语法错误
test();//表达式可以执行
var testSecond=function (){
console.log('b');
}();//可以执行,也是表达式 这种写法和立即执行函数一样,执行一次以后就被放弃了
</script>
<!-- 函数声明加+(正)-(负) !(感叹号)会变成表达式,所以加括号可以执行了,所以立即执行函数 (function (){})()也可以执行,因为外面加了括号也变为表达式了。 乘除不可以 等也可以变成立即执行函数 -->
<script>
+function testA(){
console.log("aa");
}();
</script>
<!--函数累加器 -->
<script>
function add(){
var count=0;
function demo(){
count++;
console.log(count);
}
return demo;
}
var counter=add();
counter();//1
counter();//2
counter();//3
counter();//4
counter();//5
counter();//6
</script>
<!-- 可以做缓存例1 -->
<script>
function test(){
//a和b拿的都是test的AO 共用test的AO,是同一个AO
var num=100;
function a(){
num++;
console.log(num);
}
// a被定义 a.[[scope]] 0:testAO
// 1:GO
function b(){
num--;
console.log(num);
}
//b 被定义 b.[[scope]] 0:testAO
// 1:GO
return [a,b];
}
var myArr=test();
myArr[0]();//101
//a doing a.[[scope]] 0:aAO
// 1:testAO
// 2:GO
myArr[1](); //100
//b doing b.[[scope]] 0:bAO
// 1:testAO a执行后改变的AO num=101
// 2:GO
</script>
<!-- 可以做缓存例2 -->
<script>
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();
</script>
<!-- 可以做缓存例2 -->
<script>
function test(){
var food="apple";
function a(){
food="banana"
}
function b(){
console.log(food);
}
}
</script>
<!-- 编程时要看逻辑,不能被视觉所欺骗了 -->
<!-- 一个我似懂非懂的问题 -->
<script>
function test(){
var arr=[];
for(var i=0;i<10;i++){
//arr[i]是执行语句,function是定义语句,并没有执行,函数在定义时是不执行的,里面的document根本不看,执行时才看函数里的内容,定义时根本不看里面是什么
arr[i]=function(){
document.write(i);
}
}
return arr;//for循环后,这一步保存出去,i=10,且这10个函数共用一个AO
}
var myArr=test();
for(var j=0;j<10;j++){
myArr[j]();//这里才执行 并在AO上找到变量i
}//输出10个10 因为第一个for循环结束以后,才调用的函数,在外部执行,i=10了
</script>
<!-- 一个简单的例子使我懂上面那个问题 -->
<script>
var num=100;
function test(){
console.log(num);
}
num=200;
test();//200 虽然在上面定义的,但是在下面才执行,执行时再去拿那个值
</script>
<!-- 修改后的之前那个问题,能输出0-9 -->
<script>
function test(){
var arr=[];
for(var i=0;i<10;i++){
//立即执行函数放到循环里就是10个立即执行函数
(function (j){
//立即执行函数是读到了就执行 在for循环里就执行,但是arr[j]相等的function在myArr()才会执行
arr[j]=function (){
console.log(j);
}
}(i))
}
return arr;
}
var myArr=test();
for(var j=0;j<10;j++){
myArr[j]();
}
</script>
</head>
<body>
</body>
</html>
被保存到外部的函数拿到的是对应的立即执行函数的劳动成果,一共产生了10个独一无二的立即执行函数,立即执行函数也是函数,也会有执行器上下文,立即执行函数执行完只是引用消失,
<script>
/*没有return也可产生闭包 只要一个函数嵌套另一个函数,里面的那个函数保存到外部去了,并且一直保存着外面那个函数
执行期上下文*/
var obj={}
function a(){
var aa=132;
function b(){
console.log(aa);
}
obj.fun=b
}
a()
obj.fun()
</script>
立即执行函数:执行完一次就被销毁,立即执行函数也会经历预编译,有执行器上下文
let也可以解决闭包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: darkcyan;
}
</style>
</head>
<body>
<script>
function test(){
var arr=[];
for(let i=0;i<10;i++){
//arr[i]是执行语句,function是定义语句,并没有执行,函数在定义时是不执行的,里面的document根本不看,执行时才看函数里的内容,定义时根本不看里面是什么
arr[i]=function(){
document.write(i);
}
}
return arr;//for循环后,这一步保存出去,i=10,且这10个函数共用一个AO
}
var myArr=test();
for(var j=0;j<10;j++){
myArr[j]();
}
</script>
</body>
</html>
因为{}是块级作用域。let只在当前的块级作用域内有效,下次在循环的时候,相当于又一个作用域,这次循环的i的值,在这个作用域内有效。
所以会找对应的块级作用域中的i。