一、立即执行函数
IIFE - immediately invoked function expression
自动执行,执行完成以后立即释放。
常用于初始化函数。
普通的函数在全局定义之后是存在GO中的,是不释放的,在想调用的时候就能调用 有些函数只需要运
行一次之后再也不会执行 -> 立即执行函数
就是执行之后GO中就没有了
写法
(function(){
})();
(function(){
}()); //w3c建议
传参
// 形参
;(function(a, b) {
console.log(a + b); // 3
})(1, 2); // 实参
返回值
var sum = (function(a, b) {
return a + b;
})(5, 6);
console.log(sum); // 11
错误写法
var f= (function(a,b){
console.log(a+b)
}(2,5))
f()
代码例子
var test=function(){
console.log(1)
}();
test();
立即运行1,没有分号;也行但最好写,不写很有可能报错,两边都写也行,实在不行里边都写
写test() 提示test is not a function
console.log(1)
function test3(){
console.log(1);
}();
显示Uncaught SyntaxError: Unexpected token ‘)’ 这是语法错误,不会打印1
只有表达式才能被执行符号()执行
var test1=function(){
console.log(2) //直接运行
}();
console.log(test1) //undefined
// var test1 = function a() { //一样
// console.log(2)
// }();
// console.log(test1) //undefined
2 undefined 运行完立即销毁,所以是undefined,并不是赋值不了
(function(){
console.log(123)
})();
(function test(){
console.log(123)
})();
当运行完立即销毁,所以加不加函数名是一样的
var a = function () {
console.log('a')
}()
var b = (function () {
console.log('b')
})
表达式
概念
(1+2)*3;
1;
(1);
被()括起来的都是表达式,1也是表达式,括号括起来的都是表达式,都会变成表达式。
一定是表达式才能被执行符号执行。
括号括起来的都是表达式。
表达式会忽略函数的名称。
函数声明变成表达式的方法:
+、-、!、||、&&、,、void
+function test1() {
console.log(1);
}();
+function(a, b) {
console.log(a+b)
}(1,5)
-function test2() {
console.log(2);
}();
!function test3() {
console.log(3);
}();
true && function test4() {
console.log(4);
}();
false || function test5() {
console.log(5);
}();
void function test6() {
console.log(6);
}();
2, 3, function test7() {
console.log(7);
}();
题目
function test(a,b){
console.log(1)
}(6);
/*这是对的,代码解析成*/
function test(a,b){
console.log(1)
};
(6);
/*认为(6)是表达式*/
function test(a){
}();
/*Uncaught SyntaxError: Unexpected token ')'
错的,不写不会认为是表达式,不会认为()是表达式
*/
var num=(2-1,6+5,24+1);
console.log(num);//25
闭包深入
题目1
time 41min
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function () {
document.write(i + " ");
};
}
return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
arr[j](); // 10个10
}
题目1分析
先把循环变了,循环可以变成
function test() {
var arr = [];
var i=0;
for (; i < 10; ) {
arr[i] = function () {
document.write(i + " ");
// console.log(i);//10个10
};
i++;
}
return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
arr[j](); // 10个10
}
闭包,因为arr[]数组中存着func函数,function () {document.write(i + “ “);}; 而i的值并没有确定下来,当运行完时i的值为10确定下来不再改变,所有的函数指向i最终的值10
其实与下面代码类似
function test() {
var n = 10;
var a = function () {
console.log(n);
}
var b = function () {
console.log(n)
}
return [a, b];
}
var arr = test();
arr[0]();//10
arr[1]();//10
解析
function test() {
var arr = [];
var i = 10;
/* for (; i < 10;) {
arr[i] = function () {
document.write(i + " ");
// console.log(i);//10个10
};
i++;
}*/
arr[0] = function () {
document.write(i + " ");
}
arr[1] = function () {
document.write(i + " ");
}
/*....一直到arr[9]=function (){document.write(i + " ");}
数组下标确定,不会都变成10,当数组arr[i=0]的时候,的瞬间,数组新建,数组已经确定,arr[0],arr[1]等,值不会再变了,
是给数组下标赋值,赋值完就与i没有关系了。
function没有运行,没有执行,没有AO,没有自己的AO存在它的scope中,i还没有被确定,执行时才能被确定。return出去时,i已经变成10了。也就是说AO里面的i变量最终为10,
并被每一个函数调用,引用。即使函数并没有运行。
因为把数组方法返回到全局,变量i虽然全局访问不到,但存在AO中,没有被销毁,数值为10。
arr[0]()运行时,调用、提取AO里面的i为10。
test AO存在scope中,数组方法没有运行,没有AO存在,arr函数的scope的AO中
* */
return arr;
}
var arr = test();
for (var j = 0; j < 2; j++) {
arr[j](); // 10个10
}
arr[0]、arr[0]存的i,都是test函数运行时AO中的i,test函数运行一次
解决方法1
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = (function () {
document.write(i + " ");
})();
}
}
test()
解析
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function () {
// document.write(i + " ");
console.log(i)//10个10
};
}
for (var k = 0; k < 10; k++) {
arr[k]();
}
}
test()
立即执行试试
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function () {
// document.write(i + " ");
console.log(i)
}
arr[i]();//0-9
}
for (var k = 0; k < 10; k++) {
arr[k]();//10个10
}
}
test()
for i循环,给数组方法赋值,运行了,但运行之后AO销毁了,最后还是拿着变量i,为10
立即执行函数
function test() {
var arr = [];
/* for (var i = 0; i < 10; i++) {
arr[i] = function () {
// document.write(i + " ");
console.log(i)//10个10
}
}*/
for (var i = 0; i < 10; i++) {
arr[i] = (function () {
// document.write(i + " ");
console.log(i)//0-9
})();
// arr[i]();
}
for (var k = 0; k < 10; k++) {
arr[k]();//Uncaught TypeError: arr[k] is not a function
}
}
test()
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i]=i;
}
console.log(arr)//0-9
for (var k = 0; k < 10; k++) {
console.log(arr[k]); //0-9
}
}
test()
数组是变量,变量与方法中的i是不一样的引用,数组中的i,赋值时直接确定。
方法中的i,运行时,AO产生,确定。运行之后,AO销毁,但方法声明还在,方法声明就是写方法的语句,存在了scope中,只有代码语句,如下
function test(){
var a=1;
var b=2;
var c=3;
function fu(){
var d=1;
}
}
这个代码以类似语句的方式存在scope中,占用内存
如果这段代码运行,变量a、b、c产生,占用内存,比语句占用大。
解决方法2
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function (num) {
document.write(num+ " ");
};
}
return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
arr[j](j); // 1,2...9
}
既然方法中的i会变为10,就不用i,传一个参数,传外界参数,让返回的代码调用,打印。
解决方法3
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
(function (j) {
arr[j] = function () {
document.write(j + " ");
};
})(i);
}
return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
arr[j](); // 0-9
}
结果1 2…9
把j换成i也一样
解析
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
/* (function (j) {
arr[j] = function () {
document.write(j + " ");
};
})(i);*/
function run(j) {
arr[j] = function () {
document.write(j + " ");
};
};
run(i);
}
return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
arr[j](); // 0-9
}
把i当做参数传给函数,函数执行
相当于在run方法中,新建var j赋值i,之后就与i没有关系了,arr[j]方法中拿着j,与i无关
run函数运行了10次,10次运行的AO中的j变量,都被数组方法引用都不会被销毁。每次run函数运行的i,AO中i值都不一样,从1到9。
函数运行、代码执行的i,或者变量,方法等,都是AO、GO中的变量,而不是代码中文字字面上的变量。
run函数名次运行的AO,存在数组方法声明产生的scope中,方法声明中有scope,有_loop每次运行的AO
arr[0]、arr[0]存的i,是run函数每次运行AO中的i,run函数运行多次
思路:通过函数传参、多次运行保存AO中的变量
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
/* (function (j) {
arr[j] = function () {
document.write(j + " ");
};
})(i);*/
// var j=i;//9个9
function run() {
var j=i;//0-9
arr[j] = function () {
document.write(j + " ");
};
};
run(i);
}
return arr;
}
var arr = test();
for (var j = 0; j < 10; j++) {
arr[j](); // 0-9
}
代码题目
<body>
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script type=text/javascript>
var oLi = document.querySelectorAll('li');
var oLength = oLi.length;
// for (var i = 0; i < oLength; i++) {
// oLi[i].onclick = function() {
// console.log(i);
// }
// }
for (var i = 0; i< oLength; i++) {
(function (j) {
oLi[j].onclick = function() {
console.log(j);
}
})(i)
}
</script>
</body>
逗号运算符
expr1,expr2,…
对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
console.log((1, 5, 8)); // 8
var fn = (
function test1() {
return 1;
},
function test2() {
return '2';
}
)();
console.log(typeof(fn)); // 'string'
fn是’2’, typeof返回的是字符串
面试题目
var a = 10;
if (function b(){}) { //()表达式,忽略函数名
a += typeof(b);
}
console.log(a); // '10undefined'
作业
闭包实现累加器
function sum() {
var n = 0;
function add() {
n++;
console.log(n);
}
return add;
}
var add = sum();
add();
add();
add();
add();
function sum(){
var n = 0;
function add(){
n++;
return n;
// console.log(n)
}
function reduce(){
n--;
return n;
// console.log(n)
}
return [add,reduce]
}
var ys=sum();
// ys[0]()
// ys[0]()
// console.log(sum()[0]())
// console.log(sum()[0]())
console.log( ys[0]())
console.log(ys[0]())
return也行,但没有函数保存写sum()[0]不行,必须外部变量保存,从而不让其销毁
闭包写法,1返回函数,2外部变量接收
function fnx2() {
var num = 0;
function add() {
num++;
console.log(num);
}
function sub() {
num--;
console.log(num);
}
// var optarr = [
// function add() {
// num++;
// console.log(num);
// },
// function sub() {
// num--;
// console.log(num);
// }
// ]
return {add,sub};
}
// var arr2 = fnx2();
// arr2[0](10);
// arr2[1](10);
var arr2=fnx2()
console.log(arr2);
arr2.add()//1
arr2.add()//2
一个班级:学生名字保存在一个数组里;
两个方法写在函数中的一个对象中;
第一个方法加入班级;
第二个方法离开班级;
每次加入或离开,都需要打印新的学生名单
function student() {
var students = ['张三', '李四', '王五'];
var fn = {
join: function (name) {
students.push(name);
console.log(students);
},
leave: function (name) {
var idx = students.indexOf(name);
students.splice(idx, 1);
console.log(students);
}
}
return fn;
}
var fn = student();
fn.join('小明');
fn.join('小红');
fn.leave('张三');
<script>
var x=1,
y=(z=0);
y=add(x);
function add(n){
n=n+3;
return n;
return n=n+3;
}
z=add(x);
console.log(x,y,z)
/*
AO={
n->undefined->1->n=n+3=4
}
因为n是参数,函数运行时产生AO,n才初始化为undefined,把x的值1赋值给n,n=1,之后n=n+3等于4,函数运行完AO销毁,n就销毁了,之后再运行继续n的初始化,继续上述流程
*/
</script>