一、立即执行函数
在全局作用域下声明的函数是存在GO中的,它可以在全局下的任何地方去执行
// 在全局下声明的函数,它是存储在GO中的;它可以在全局下的任何地方执行function test1(){console.log(1);}function test2(){console.log(2);}console.log(2);function test3(){test1();}test3();
1.1、什么是IIFE?以及IIFE的特点
- IIFE:immediately-invoked function expression 立即执行函数
- IIFE的特点:立即执行,执行完后就立即释放
立即执行函数 -> 初始化函数
// 什么是IIFE?IIFE的特点是什么?// IIFE:immediately-invoked function expression 立即执行函数// 立即执行函数:会立即执行,执行完后就立即释放// 立即执行函数 -> 初始化函数(function(a, b){console.log(a + b);})(1, 2);
1.2、IIFE的几种书写方式
W3C推荐的书写方式
// 立即执行函数的书写方式// W3C推荐(function(){console.log('W3C推荐的书写方式');}());
平时开发者常用的书写形式
// 平时常用的书写方式(function(){console.log('平时书写常用');})()
接收立即执行函数的返回值
IIFE执行完就立即销毁了,所以没有必要设置函数名「写了函数的名字,JS引擎也会自动忽略掉」,如果想要获取到函数执行后的结果,那么可以在函数外定义一个变量,函数内部将结果return出去
// 接收立即执行函数的返回值// IIFE执行完就立即销毁了,所以没有必要设置函数名「写了函数的名字,JS引擎也会自动忽略掉」,如果想要获取到函数执行后的结果,那么可以在函数外定义一个变量,函数内部将结果return出去var res = (function(a, b){return a + b;}(1, 2));console.log(res);
二、表达式和括号执行符号
一定是只有表达式才能被执行符号执行
- 括号括任何东西进去,最终括号里面的东西都会变为表达式
注意:IIFE在执行的时候会自动忽略掉函数名
// 表达式和括号执行符号// 一定是只有表达式才能被执行符号执行// 括号包起来的东西都是表达式// 以下几种皆为表达式var func = function(){};(function func(){});(1);
注意:IIFE在执行的时候会自动忽略掉函数名
下面能够执行成功的是// 注意:IIFE在执行的时候会自动忽略掉函数名// 下面能够执行成功的是function test1(){console.log(1);}(); // 语法错误,因为前面部分不是表达式,不能被执行符号执行var test2 = function(){console.log(2);}(); // 可以被执行,因为前面是表达式(function test3(){console.log(3);}()); // 可以被执行,这种是W3C推荐的写法(function test4(){console.log(4);})(); // 可以被执行,这也是工作中常用的写法,小括号括起来的都是表达式
三、如何将函数声明变为函数表达式
函数声明变成函数表达式的方法:+、 -、 !、~、 假 || 函数、真 && 函数
- 函数声明变为函数表达式之后,函数名会自动被忽略掉
W3C推荐的IIFE写法
// 将函数声明变成函数表达式的几种方法:+、-、!、~、假 || 函数、真 && 函数// 将函数声明变为函数表达式的时候,会自动忽略掉函数名,因为IIFE是立即执行,执行完后立即释放掉的// 小括号包起来的都是表达式(function(){console.log('这是W3C推荐的写法');}());
工作中常见到的写法
// 工作常见到的IIFE(function(){console.log('这是工作中常见到的写法');})();
在普通函数前面加上+,可以变为函数表达式
// 在普通函数前面加上+,可以变为函数表达式+ function func1(){console.log('在普通函数前面加上+,可以变为函数表达式');}();
在普通函数前面加上-,也可以变为函数表达式
// 在普通函数前面加上-,也可以变为函数表达式- function func2(){console.log('在普通函数前面加上-,也可以变为函数表达式');}();
在普通函数前面加上!,也可以变为函数表达式
// 在普通函数前面加上!,也可以变为函数表达式! function func3(){console.log('在普通函数前面加上!,也可以变为函数表达式');}();
在普通函数前面加上~,也可以变为函数表达式
// 在普通函数前面加上~,也可以变为函数表达式~ function func4(){console.log('在普通函数前面加上~,也可以变为函数表达式');}();
四、逗号运算符
逗号运算符类似逻辑运算符,它只返回逗号后面的最后一个
// 逗号运算符// 逗号运算符类似于逻辑运算符,它只返回逗号后面的最后一个console.log(1, 2);// 面试题var num = (2 - 1, 6 + 5, 24 + 1);console.log(num);
下面函数执行会报错吗?为什么?
// 下面函数执行会报错吗?为什么?// 不会报错,但同时函数也不会被执行,因为它会把末尾的(1, 2)解析为表达式,但是如果最末未的小括号里不传值,就会报错function test(a, b){console.log(a + b);}(1, 2);
五、面试题
5.1、面试题一
打印结果是什么?为什么?
// 面试题// 打印结果是什么?为什么?// 打印结果是十个10,这是由于闭包机制所造成的,当循环给数组赋值匿名函数的时候,匿名函数并没有被执行,当i = 10的时候,for循环的条件不满足,此时循环结束,但是此时的i已经是10了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);for(var j = 0; j < 10; j++){myArr[j]();}
如果我想打印0~9,那么上面代码需要如何修改呢?
// 如果我想打印0~9,那么上面代码需要如何修改呢?// 循环的时候立即执行function func(){var arr = [];for(var i = 0; i < 10; i++){(function(j){arr[j] = function(){document.write(j + ' ');}}(i));}return arr;};var myArr = func();for(var j = 0; j < 10; j++){myArr[j]();}
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]();
5.2、面试题二
点击每一个li打印出的结果是什么?为什么?
<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>// 获取所有的li,获取到的结果是一个类数组结合 NodeListvar oLi = document.querySelectorAll('li');// 循环给每一个li绑定点击事件for(var i = 0; i < oLi.length; i++){oLi[i].onclick = function(){console.log(i);}}
如果我想让点击每一个li的时候,输出的结果是1~5,该如何做呢?
<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>// 利用自执行函数的原理var oLi = document.querySelectorAll('li');for(var i = 0; i < oLi.length; i++){(function(j){oLi[j].onclick = function(){console.log(j + 1);}}(i))}
5.3、面试题三
注意:刚开始做的时候,我做错了,需要特别留意一下这个题
var num = (1, 3);console.log(num);var fn = (function func1(){return 1;},function func2(){return "2";})();console.log(typeof(fn));
5.4、面试题四
- 括号括起来的都是表达式,表达式是会忽略函数名的
typeof一个未被声明的变量,结果是’undefined’
// 面试题// 括号括起来的都是表达式,表达式是会忽略函数名的 function b(){} -> function(){}var a = 10;if(function b(){}){a += typeof(b);}console.log(a);
六、作业
6.1、累加器
作业一:累加器,从0开始,每次执行函数都在原来的基础上加1
// 作业一:累加器,从0开始,每次执行函数都在原来的基础上加1function func(){var num = 0;var operation = {add: function(){num++;console.log(num);}}return operation;}var res = func();res.add();res.add();
6.2、缓存器
一个班级的学生保存在一个数组里,两个方法写在函数中,第一个方法是加入班级,第二个方法是离开班级;每次加入或者是离开都要打印新的学生名单
// 缓存器// 一个班级的学生保存在一个数组里,两个方法写在函数中,第一个方法是加入班级,第二个方法是离开班级;每次加入或者是离开都要打印新的学生名单function myClass(){var students = [];var total = 6;var operation = {join: function(name){students.push(name);console.log(students);},leave: function(name){if(students.length == this.total){console.log('全部到课');}for(var i = 0; i < students.length; i++){var item = students[i];if(item === name){students.splice(i, 1);}}console.log(name + '未到课');},classOver: function(){students = [];console.log('下课时间到');console.log(students);}}return operation;}var obj = myClass();obj.join('张三');obj.join('李四');obj.join('王五');obj.join('赵六');obj.leave('张三');obj.classOver();
function myClass(){var students = [];var operation = {join: function(name){students.push(name);console.log(students);},leave: function(name){var index = students.indexOf(name);if(index !== -1){students.splice(index, 1);console.log(name + '未到课');}},classOver: function(){students = [];console.log('下课时间到');console.log(students);}}return operation;}var obj = myClass();obj.join('张三');obj.join('李四');obj.join('王五');obj.join('赵六');obj.leave('张三');obj.classOver();
