目录
1. 立即执行函数 IIFE -immediately-invoked function expression
全局的函数都保存在GO中,不释放,想调用的时候可以随时调用
function test1() {
console.log(1);
}
function test2() {
console.log(2);
}
test2();
function test3() {
test1();
}
test3();
// 2 1
1.1 特点
- 自动执行
- 执行完成之后立即释放
立即执行函数 的功能性称呼:初始化函数
1.2 写法
-
写法一
函数括起来之后再加(),也就是函数的执行
一定是表达式才能被执行符号()执行
(function(){ })(); // 函数括起来之后再加(),也就是函数的执行
-
写法二
括号里面写函数声明,这个函数经过括号的包裹也就变成了表达式
括号包任何东西都叫表达式,它也能转换成表达式
把函数声明变成表达式之后,函数名就被自动忽略了
// 写法2 (function(){ }()); // W3C 建议 // 括号里面写函数声明,这个函数经过括号的包裹也就变成了表达式 // 括号包任何东西都叫表达式,它也能转换成表达式
问题:下方代码是否能执行
function test(){
}();
// 报错:语法错误
var test = function(){
console.log(1);
}(); // 可以执行
(function test(){
console.log(1);
})(); // 可以执行,标准的立即执行函数
var test2 = function(){
console.log(1);
}(); // 可以执行
function test3(){
console.log(1);
}(); // 不可以执行,报错
// 一定是表达式才能被执行符号执行
// 括号包任何东西都叫表达式,它也能转换成表达式
需求:以下函数立即执行,并拿到值,执行完立即释放
add(1, 2);
function add(a, b) {
console.log(a + b);
}
(function test(){
var a = 1,
b = 2;
console.log(a + b);
}());
test; // 这个时候报错:test is not defined,从侧面印证了执行完立即释放;()->函数的执行符号
// 传参、返回值
var num = (function(a, b){
return a + b;
}(2, 4));
console.log(num);
var test = function(){
console.log(1);
}
console.log(test); // function(){...} 匿名函数
var test1 = function(){
console.log(2);
}();
console.log(test1); // 2 undefined
// 证明了立即执行,执行完就销毁
1.3 将函数声明变成表达式的方法
// 1. 函数声明前加上符号 + - ! || &&
+ function test(){
console.log(1);
}()
总结:将函数声明转换为表达式后就可以使用执行符号,立即执行该函数,并且该函数的函数名就自动被忽略掉了
1.4 面试题
1.4.1 下面代码会报错吗
function test(a){
console.log(1);
}(6)
不会报错,括号里面传了值,就将其理解为一个表达式 (6),不将其认为是一个立即执行符号,如果是什么都不传,就会将其认为是立即执行符号,就会报错
1.4.2 for循环中返回结果是什么?为什么?
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(){
document.write(i + ' ');
}
}
return arr; // 这里形成了闭包
}
var myArr = test();
console.log(myArr); // [f,f,..] 是个匿名函数
for(var j = 0; j < 10; j++){
myArr[j](); // 返回结果是什么?为什么
}
答: 十个10
因为每次给arr[i]赋值的时候,只是赋值了一个匿名函数,并没有执行,return 的时候,test的AO中 i已经变为10了,而且被arr中的每一个函数拽住,等到执行的时候,就都是 10 了
i 的值相当于下面的 test 中的 n
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]();
arr[1]();
变形:上题中怎么能正确打印1-9
// 方法1:循环时立即执行
function test(){
for(var i = 0; i < 10; i++){
(function(){
document.write(i + ' ');
})() // 这里变为立即执行函数
}
}
test();
// 方法2:传参
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(num){ // 传参
document.write(num + ' ');
}
}
return arr;
}
var myArr = test();
console.log(myArr); //
for(var j = 0; j < 10; j++){
myArr[j](j);
}
// 方法3:保存每次立即执行的值(最常用)
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
(function(j){ // 每一次循环的时候,把 i 保存进立即函数里 ⭐
arr[j] = function(){ // 每次替换的时候,arr[j]和j都会被替换,值不一样,循环的是立即执行函数
document.write(j + ' ');
}
})(i)
}
return arr;
}
var myArr = test();
console.log(myArr); //
for(var j = 0; j < 10; j++){
myArr[j]();
}
1.4.3 代码中点击 li返回的是什么
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script type="text/javascript">
var oLi = document.querySelectorAll('li');
for(var i = 0; i < oLi.length; i++){
oLi[i].onclick = function(){
console.log(i);
}
}
</script>
// 答:每次点击返回的都是5
// 解决方法:立即执行函数
<script type="text/javascript">
var oLi = document.querySelectorAll('li');
for(var i = 0; i < oLi.length; i++){
(function(j){
oLi[j].onclick = function(){
console.log(j);
}
})(i)
}
</script>
1.4.4 代码中打印什么⭐
var a = 10;
if(function b(){}){ // 函数声明被()括起来了,变成表达式,名称被忽略了 ⭐
a += typeof(b); // 所以没有 b
}
console.log(a); // 10undefined
2. 逗号运算符
返回最后一个逗号后面的值 ⭐
var num = (2 - 1, 6 + 5, 24 + 1);
console.log(num); // 25
面试题
var fn = (
function test1(){
return 1;
},
function test2(){
return '2';
}
)()
console.log(typeof(fn)); // string
3. 作业
-
累加器,初始值是0,写个闭包,执行一次函数,增加1打印一次
function acc(){ var num = 0; function add(){ console.log(++num); } return add; } var fn = acc(); fn();
-
缓存器,闭包,一个班级,学生的名字保存在一个数组里,两个方法写在函数中的一个对象中,第一个方法加入班级,第二个方法离开班级,每次加入或离开,传入学生的名字都需要打印新的学生名单
function myClass(){ var students = []; return { join: function(name){ students.push(name); console.log(students); }, leave: function(name){ // 方法 1 var idx = students.indexOf(name); if(idx !== -1) { students.splice(idx, 1); } // 方法 2 // for(var i = 0; i < students.length; i++) { // var item = students[i]; // 优化for循环性能的一种方法 // if(item === name){ // students.splice(i, 1); // } // } console.log(students); } } } var c = myClass(); c.join('Andy'); c.join('Tom'); c.join('Cindy'); c.leave('Tom');