一、立即执行函数

在全局作用域下声明的函数是存在GO中的,它可以在全局下的任何地方去执行

  1. // 在全局下声明的函数,它是存储在GO中的;它可以在全局下的任何地方执行
  2. function test1(){
  3. console.log(1);
  4. }
  5. function test2(){
  6. console.log(2);
  7. }
  8. console.log(2);
  9. function test3(){
  10. test1();
  11. }
  12. test3();

1.1、什么是IIFE?以及IIFE的特点

  • IIFE:immediately-invoked function expression 立即执行函数
  • IIFE的特点:立即执行,执行完后就立即释放
  • 立即执行函数 -> 初始化函数

    1. // 什么是IIFE?IIFE的特点是什么?
    2. // IIFE:immediately-invoked function expression 立即执行函数
    3. // 立即执行函数:会立即执行,执行完后就立即释放
    4. // 立即执行函数 -> 初始化函数
    5. (function(a, b){
    6. console.log(a + b);
    7. })(1, 2);

    1.2、IIFE的几种书写方式

    W3C推荐的书写方式

    1. // 立即执行函数的书写方式
    2. // W3C推荐
    3. (function(){
    4. console.log('W3C推荐的书写方式');
    5. }());

    平时开发者常用的书写形式

    1. // 平时常用的书写方式
    2. (function(){
    3. console.log('平时书写常用');
    4. })()
  • 接收立即执行函数的返回值

  • IIFE执行完就立即销毁了,所以没有必要设置函数名「写了函数的名字,JS引擎也会自动忽略掉」,如果想要获取到函数执行后的结果,那么可以在函数外定义一个变量,函数内部将结果return出去

    1. // 接收立即执行函数的返回值
    2. // IIFE执行完就立即销毁了,所以没有必要设置函数名「写了函数的名字,JS引擎也会自动忽略掉」,如果想要获取到函数执行后的结果,那么可以在函数外定义一个变量,函数内部将结果return出去
    3. var res = (function(a, b){
    4. return a + b;
    5. }(1, 2));
    6. console.log(res);

    二、表达式和括号执行符号

  • 一定是只有表达式才能被执行符号执行

  • 括号括任何东西进去,最终括号里面的东西都会变为表达式
  • 注意:IIFE在执行的时候会自动忽略掉函数名

    1. // 表达式和括号执行符号
    2. // 一定是只有表达式才能被执行符号执行
    3. // 括号包起来的东西都是表达式
    4. // 以下几种皆为表达式
    5. var func = function(){};
    6. (function func(){});
    7. (1);

    注意:IIFE在执行的时候会自动忽略掉函数名
    下面能够执行成功的是

    1. // 注意:IIFE在执行的时候会自动忽略掉函数名
    2. // 下面能够执行成功的是
    3. function test1(){
    4. console.log(1);
    5. }(); // 语法错误,因为前面部分不是表达式,不能被执行符号执行
    6. var test2 = function(){
    7. console.log(2);
    8. }(); // 可以被执行,因为前面是表达式
    9. (function test3(){
    10. console.log(3);
    11. }()); // 可以被执行,这种是W3C推荐的写法
    12. (function test4(){
    13. console.log(4);
    14. })(); // 可以被执行,这也是工作中常用的写法,小括号括起来的都是表达式

    三、如何将函数声明变为函数表达式

  • 函数声明变成函数表达式的方法:+、 -、 !、~、 假 || 函数、真 && 函数

  • 函数声明变为函数表达式之后,函数名会自动被忽略掉

W3C推荐的IIFE写法

  1. // 将函数声明变成函数表达式的几种方法:+、-、!、~、假 || 函数、真 && 函数
  2. // 将函数声明变为函数表达式的时候,会自动忽略掉函数名,因为IIFE是立即执行,执行完后立即释放掉的
  3. // 小括号包起来的都是表达式
  4. (function(){
  5. console.log('这是W3C推荐的写法');
  6. }());

工作中常见到的写法

  1. // 工作常见到的IIFE
  2. (function(){
  3. console.log('这是工作中常见到的写法');
  4. })();

在普通函数前面加上+,可以变为函数表达式

  1. // 在普通函数前面加上+,可以变为函数表达式
  2. + function func1(){
  3. console.log('在普通函数前面加上+,可以变为函数表达式');
  4. }();

在普通函数前面加上-,也可以变为函数表达式

  1. // 在普通函数前面加上-,也可以变为函数表达式
  2. - function func2(){
  3. console.log('在普通函数前面加上-,也可以变为函数表达式');
  4. }();

在普通函数前面加上!,也可以变为函数表达式

  1. // 在普通函数前面加上!,也可以变为函数表达式
  2. ! function func3(){
  3. console.log('在普通函数前面加上!,也可以变为函数表达式');
  4. }();

在普通函数前面加上~,也可以变为函数表达式

  1. // 在普通函数前面加上~,也可以变为函数表达式
  2. ~ function func4(){
  3. console.log('在普通函数前面加上~,也可以变为函数表达式');
  4. }();

四、逗号运算符

逗号运算符类似逻辑运算符,它只返回逗号后面的最后一个

  1. // 逗号运算符
  2. // 逗号运算符类似于逻辑运算符,它只返回逗号后面的最后一个
  3. console.log(1, 2);
  4. // 面试题
  5. var num = (2 - 1, 6 + 5, 24 + 1);
  6. console.log(num);

下面函数执行会报错吗?为什么?

  1. // 下面函数执行会报错吗?为什么?
  2. // 不会报错,但同时函数也不会被执行,因为它会把末尾的(1, 2)解析为表达式,但是如果最末未的小括号里不传值,就会报错
  3. function test(a, b){
  4. console.log(a + b);
  5. }(1, 2);

五、面试题

5.1、面试题一

打印结果是什么?为什么?

  1. // 面试题
  2. // 打印结果是什么?为什么?
  3. // 打印结果是十个10,这是由于闭包机制所造成的,当循环给数组赋值匿名函数的时候,匿名函数并没有被执行,当i = 10的时候,for循环的条件不满足,此时循环结束,但是此时的i已经是10了
  4. function test(){
  5. var arr = [];
  6. for(var i = 0; i < 10; i++){
  7. arr[i] = function(){
  8. document.write(i + ' ');
  9. };
  10. }
  11. return arr;
  12. }
  13. var myArr = test();
  14. // console.log(myArr);
  15. for(var j = 0; j < 10; j++){
  16. myArr[j]();
  17. }

如果我想打印0~9,那么上面代码需要如何修改呢?

  1. // 如果我想打印0~9,那么上面代码需要如何修改呢?
  2. // 循环的时候立即执行
  3. function func(){
  4. var arr = [];
  5. for(var i = 0; i < 10; i++){
  6. (function(j){
  7. arr[j] = function(){
  8. document.write(j + ' ');
  9. }
  10. }(i));
  11. }
  12. return arr;
  13. };
  14. var myArr = func();
  15. for(var j = 0; j < 10; j++){
  16. myArr[j]();
  17. }
  1. function test(){
  2. var n = 10;
  3. var a = function(){
  4. console.log(n);
  5. }
  6. var b = function(){
  7. console.log(n);
  8. }
  9. return [a, b];
  10. }
  11. var arr = test();
  12. arr[0]();
  13. arr[1]();

5.2、面试题二

点击每一个li打印出的结果是什么?为什么?

  1. <ul>
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. <li>5</li>
  7. </ul>
  8. // 获取所有的li,获取到的结果是一个类数组结合 NodeList
  9. var oLi = document.querySelectorAll('li');
  10. // 循环给每一个li绑定点击事件
  11. for(var i = 0; i < oLi.length; i++){
  12. oLi[i].onclick = function(){
  13. console.log(i);
  14. }
  15. }

如果我想让点击每一个li的时候,输出的结果是1~5,该如何做呢?

  1. <ul>
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. <li>5</li>
  7. </ul>
  8. // 利用自执行函数的原理
  9. var oLi = document.querySelectorAll('li');
  10. for(var i = 0; i < oLi.length; i++){
  11. (function(j){
  12. oLi[j].onclick = function(){
  13. console.log(j + 1);
  14. }
  15. }(i))
  16. }

5.3、面试题三

注意:刚开始做的时候,我做错了,需要特别留意一下这个题

  1. var num = (1, 3);
  2. console.log(num);
  3. var fn = (
  4. function func1(){
  5. return 1;
  6. },
  7. function func2(){
  8. return "2";
  9. }
  10. )();
  11. console.log(typeof(fn));

5.4、面试题四

  • 括号括起来的都是表达式,表达式是会忽略函数名的
  • typeof一个未被声明的变量,结果是’undefined’

    1. // 面试题
    2. // 括号括起来的都是表达式,表达式是会忽略函数名的 function b(){} -> function(){}
    3. var a = 10;
    4. if(function b(){}){
    5. a += typeof(b);
    6. }
    7. console.log(a);

    六、作业

    6.1、累加器

    作业一:累加器,从0开始,每次执行函数都在原来的基础上加1

    1. // 作业一:累加器,从0开始,每次执行函数都在原来的基础上加1
    2. function func(){
    3. var num = 0;
    4. var operation = {
    5. add: function(){
    6. num++;
    7. console.log(num);
    8. }
    9. }
    10. return operation;
    11. }
    12. var res = func();
    13. res.add();
    14. res.add();

    6.2、缓存器

    一个班级的学生保存在一个数组里,两个方法写在函数中,第一个方法是加入班级,第二个方法是离开班级;每次加入或者是离开都要打印新的学生名单

    1. // 缓存器
    2. // 一个班级的学生保存在一个数组里,两个方法写在函数中,第一个方法是加入班级,第二个方法是离开班级;每次加入或者是离开都要打印新的学生名单
    3. function myClass(){
    4. var students = [];
    5. var total = 6;
    6. var operation = {
    7. join: function(name){
    8. students.push(name);
    9. console.log(students);
    10. },
    11. leave: function(name){
    12. if(students.length == this.total){
    13. console.log('全部到课');
    14. }
    15. for(var i = 0; i < students.length; i++){
    16. var item = students[i];
    17. if(item === name){
    18. students.splice(i, 1);
    19. }
    20. }
    21. console.log(name + '未到课');
    22. },
    23. classOver: function(){
    24. students = [];
    25. console.log('下课时间到');
    26. console.log(students);
    27. }
    28. }
    29. return operation;
    30. }
    31. var obj = myClass();
    32. obj.join('张三');
    33. obj.join('李四');
    34. obj.join('王五');
    35. obj.join('赵六');
    36. obj.leave('张三');
    37. obj.classOver();
    1. function myClass(){
    2. var students = [];
    3. var operation = {
    4. join: function(name){
    5. students.push(name);
    6. console.log(students);
    7. },
    8. leave: function(name){
    9. var index = students.indexOf(name);
    10. if(index !== -1){
    11. students.splice(index, 1);
    12. console.log(name + '未到课');
    13. }
    14. },
    15. classOver: function(){
    16. students = [];
    17. console.log('下课时间到');
    18. console.log(students);
    19. }
    20. }
    21. return operation;
    22. }
    23. var obj = myClass();
    24. obj.join('张三');
    25. obj.join('李四');
    26. obj.join('王五');
    27. obj.join('赵六');
    28. obj.leave('张三');
    29. obj.classOver();