一、立即执行函数

IIFE - immediately invoked function expression
自动执行,执行完成以后立即释放。
常用于初始化函数。

普通的函数在全局定义之后是存在GO中的,是不释放的,在想调用的时候就能调用 有些函数只需要运
行一次之后再也不会执行 -> 立即执行函数
就是执行之后GO中就没有了

写法

  1. (function(){
  2. })();
  3. (function(){
  4. }()); //w3c建议

不写;也行,没有任何问题

传参

  1. // 形参
  2. ;(function(a, b) {
  3. console.log(a + b); // 3
  4. })(1, 2); // 实参

返回值

  1. var sum = (function(a, b) {
  2. return a + b;
  3. })(5, 6);
  4. console.log(sum); // 11

错误写法

  1. var f= (function(a,b){
  2. console.log(a+b)
  3. }(2,5))
  4. f()

f is not a function

代码例子

  1. var test=function(){
  2. console.log(1)
  3. }();
  4. test();

立即运行1,没有分号;也行但最好写,不写很有可能报错,两边都写也行,实在不行里边都写
写test() 提示test is not a function

  1. console.log(1)
  2. function test3(){
  3. console.log(1);
  4. }();

显示Uncaught SyntaxError: Unexpected token ‘)’ 这是语法错误,不会打印1
只有表达式才能被执行符号()执行

  1. var test1=function(){
  2. console.log(2) //直接运行
  3. }();
  4. console.log(test1) //undefined
  5. // var test1 = function a() { //一样
  6. // console.log(2)
  7. // }();
  8. // console.log(test1) //undefined

2 undefined 运行完立即销毁,所以是undefined,并不是赋值不了

  1. (function(){
  2. console.log(123)
  3. })();
  4. (function test(){
  5. console.log(123)
  6. })();

当运行完立即销毁,所以加不加函数名是一样的

  1. var a = function () {
  2. console.log('a')
  3. }()
  4. var b = (function () {
  5. console.log('b')
  6. })

a可以直接运行,b不可以

表达式

概念

  1. (1+2)*3;
  2. 1;
  3. (1);

被()括起来的都是表达式,1也是表达式,括号括起来的都是表达式,都会变成表达式。

一定是表达式才能被执行符号执行。
括号括起来的都是表达式。
表达式会忽略函数的名称。
函数声明变成表达式的方法:
+、-、!、||、&&、,、void

  1. +function test1() {
  2. console.log(1);
  3. }();
  4. +function(a, b) {
  5. console.log(a+b)
  6. }(1,5)
  7. -function test2() {
  8. console.log(2);
  9. }();
  10. !function test3() {
  11. console.log(3);
  12. }();
  13. true && function test4() {
  14. console.log(4);
  15. }();
  16. false || function test5() {
  17. console.log(5);
  18. }();
  19. void function test6() {
  20. console.log(6);
  21. }();
  22. 2, 3, function test7() {
  23. console.log(7);
  24. }();

题目

  1. function test(a,b){
  2. console.log(1)
  3. }(6);
  4. /*这是对的,代码解析成*/
  5. function test(a,b){
  6. console.log(1)
  7. };
  8. (6);
  9. /*认为(6)是表达式*/
  10. function test(a){
  11. }();
  12. /*Uncaught SyntaxError: Unexpected token ')'
  13. 错的,不写不会认为是表达式,不会认为()是表达式
  14. */
  1. var num=(2-1,6+5,24+1);
  2. console.log(num);//25

,返回最好一个,也是种运算符

闭包深入

题目1

time 41min

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. arr[i] = function () {
  5. document.write(i + " ");
  6. };
  7. }
  8. return arr;
  9. }
  10. var arr = test();
  11. for (var j = 0; j < 10; j++) {
  12. arr[j](); // 10个10
  13. }

10个10

题目1分析

先把循环变了,循环可以变成

  1. function test() {
  2. var arr = [];
  3. var i=0;
  4. for (; i < 10; ) {
  5. arr[i] = function () {
  6. document.write(i + " ");
  7. // console.log(i);//10个10
  8. };
  9. i++;
  10. }
  11. return arr;
  12. }
  13. var arr = test();
  14. for (var j = 0; j < 10; j++) {
  15. arr[j](); // 10个10
  16. }

闭包,因为arr[]数组中存着func函数,function () {document.write(i + “ “);}; 而i的值并没有确定下来,当运行完时i的值为10确定下来不再改变,所有的函数指向i最终的值10

其实与下面代码类似

  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]();//10
  13. arr[1]();//10

解析

  1. function test() {
  2. var arr = [];
  3. var i = 10;
  4. /* for (; i < 10;) {
  5. arr[i] = function () {
  6. document.write(i + " ");
  7. // console.log(i);//10个10
  8. };
  9. i++;
  10. }*/
  11. arr[0] = function () {
  12. document.write(i + " ");
  13. }
  14. arr[1] = function () {
  15. document.write(i + " ");
  16. }
  17. /*....一直到arr[9]=function (){document.write(i + " ");}
  18. 数组下标确定,不会都变成10,当数组arr[i=0]的时候,的瞬间,数组新建,数组已经确定,arr[0],arr[1]等,值不会再变了,
  19. 是给数组下标赋值,赋值完就与i没有关系了。
  20. function没有运行,没有执行,没有AO,没有自己的AO存在它的scope中,i还没有被确定,执行时才能被确定。return出去时,i已经变成10了。也就是说AO里面的i变量最终为10,
  21. 并被每一个函数调用,引用。即使函数并没有运行。
  22. 因为把数组方法返回到全局,变量i虽然全局访问不到,但存在AO中,没有被销毁,数值为10。
  23. arr[0]()运行时,调用、提取AO里面的i为10。
  24. test AO存在scope中,数组方法没有运行,没有AO存在,arr函数的scope的AO中
  25. * */
  26. return arr;
  27. }
  28. var arr = test();
  29. for (var j = 0; j < 2; j++) {
  30. arr[j](); // 10个10
  31. }

arr[0]、arr[0]存的i,都是test函数运行时AO中的i,test函数运行一次

解决方法1

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. arr[i] = (function () {
  5. document.write(i + " ");
  6. })();
  7. }
  8. }
  9. test()

解析

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. arr[i] = function () {
  5. // document.write(i + " ");
  6. console.log(i)//10个10
  7. };
  8. }
  9. for (var k = 0; k < 10; k++) {
  10. arr[k]();
  11. }
  12. }
  13. test()

立即执行试试

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. arr[i] = function () {
  5. // document.write(i + " ");
  6. console.log(i)
  7. }
  8. arr[i]();//0-9
  9. }
  10. for (var k = 0; k < 10; k++) {
  11. arr[k]();//10个10
  12. }
  13. }
  14. test()

for i循环,给数组方法赋值,运行了,但运行之后AO销毁了,最后还是拿着变量i,为10

立即执行函数

  1. function test() {
  2. var arr = [];
  3. /* for (var i = 0; i < 10; i++) {
  4. arr[i] = function () {
  5. // document.write(i + " ");
  6. console.log(i)//10个10
  7. }
  8. }*/
  9. for (var i = 0; i < 10; i++) {
  10. arr[i] = (function () {
  11. // document.write(i + " ");
  12. console.log(i)//0-9
  13. })();
  14. // arr[i]();
  15. }
  16. for (var k = 0; k < 10; k++) {
  17. arr[k]();//Uncaught TypeError: arr[k] is not a function
  18. }
  19. }
  20. test()
  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. arr[i]=i;
  5. }
  6. console.log(arr)//0-9
  7. for (var k = 0; k < 10; k++) {
  8. console.log(arr[k]); //0-9
  9. }
  10. }
  11. test()

数组是变量,变量与方法中的i是不一样的引用,数组中的i,赋值时直接确定。
方法中的i,运行时,AO产生,确定。运行之后,AO销毁,但方法声明还在,方法声明就是写方法的语句,存在了scope中,只有代码语句,如下

  1. function test(){
  2. var a=1;
  3. var b=2;
  4. var c=3;
  5. function fu(){
  6. var d=1;
  7. }
  8. }

这个代码以类似语句的方式存在scope中,占用内存
如果这段代码运行,变量a、b、c产生,占用内存,比语句占用大。

解决方法2

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. arr[i] = function (num) {
  5. document.write(num+ " ");
  6. };
  7. }
  8. return arr;
  9. }
  10. var arr = test();
  11. for (var j = 0; j < 10; j++) {
  12. arr[j](j); // 1,2...9
  13. }

既然方法中的i会变为10,就不用i,传一个参数,传外界参数,让返回的代码调用,打印。

解决方法3

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. (function (j) {
  5. arr[j] = function () {
  6. document.write(j + " ");
  7. };
  8. })(i);
  9. }
  10. return arr;
  11. }
  12. var arr = test();
  13. for (var j = 0; j < 10; j++) {
  14. arr[j](); // 0-9
  15. }

结果1 2…9
把j换成i也一样

解析

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. /* (function (j) {
  5. arr[j] = function () {
  6. document.write(j + " ");
  7. };
  8. })(i);*/
  9. function run(j) {
  10. arr[j] = function () {
  11. document.write(j + " ");
  12. };
  13. };
  14. run(i);
  15. }
  16. return arr;
  17. }
  18. var arr = test();
  19. for (var j = 0; j < 10; j++) {
  20. arr[j](); // 0-9
  21. }

把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中的变量

  1. function test() {
  2. var arr = [];
  3. for (var i = 0; i < 10; i++) {
  4. /* (function (j) {
  5. arr[j] = function () {
  6. document.write(j + " ");
  7. };
  8. })(i);*/
  9. // var j=i;//9个9
  10. function run() {
  11. var j=i;//0-9
  12. arr[j] = function () {
  13. document.write(j + " ");
  14. };
  15. };
  16. run(i);
  17. }
  18. return arr;
  19. }
  20. var arr = test();
  21. for (var j = 0; j < 10; j++) {
  22. arr[j](); // 0-9
  23. }

代码题目

  1. <body>
  2. <ul>
  3. <li>0</li>
  4. <li>1</li>
  5. <li>2</li>
  6. <li>3</li>
  7. <li>4</li>
  8. </ul>
  9. <script type=text/javascript>
  10. var oLi = document.querySelectorAll('li');
  11. var oLength = oLi.length;
  12. // for (var i = 0; i < oLength; i++) {
  13. // oLi[i].onclick = function() {
  14. // console.log(i);
  15. // }
  16. // }
  17. for (var i = 0; i< oLength; i++) {
  18. (function (j) {
  19. oLi[j].onclick = function() {
  20. console.log(j);
  21. }
  22. })(i)
  23. }
  24. </script>
  25. </body>

逗号运算符

expr1,expr2,…
对它的每个操作数求值(从左到右),并返回最后一个操作数的值。

  1. console.log((1, 5, 8)); // 8
  2. var fn = (
  3. function test1() {
  4. return 1;
  5. },
  6. function test2() {
  7. return '2';
  8. }
  9. )();
  10. console.log(typeof(fn)); // 'string'

fn是’2’, typeof返回的是字符串

面试题目

  1. var a = 10;
  2. if (function b(){}) { //()表达式,忽略函数名
  3. a += typeof(b);
  4. }
  5. console.log(a); // '10undefined'

作业

闭包实现累加器

  1. function sum() {
  2. var n = 0;
  3. function add() {
  4. n++;
  5. console.log(n);
  6. }
  7. return add;
  8. }
  9. var add = sum();
  10. add();
  11. add();
  12. add();
  13. add();
  1. function sum(){
  2. var n = 0;
  3. function add(){
  4. n++;
  5. return n;
  6. // console.log(n)
  7. }
  8. function reduce(){
  9. n--;
  10. return n;
  11. // console.log(n)
  12. }
  13. return [add,reduce]
  14. }
  15. var ys=sum();
  16. // ys[0]()
  17. // ys[0]()
  18. // console.log(sum()[0]())
  19. // console.log(sum()[0]())
  20. console.log( ys[0]())
  21. console.log(ys[0]())

return也行,但没有函数保存写sum()[0]不行,必须外部变量保存,从而不让其销毁
闭包写法,1返回函数,2外部变量接收

  1. function fnx2() {
  2. var num = 0;
  3. function add() {
  4. num++;
  5. console.log(num);
  6. }
  7. function sub() {
  8. num--;
  9. console.log(num);
  10. }
  11. // var optarr = [
  12. // function add() {
  13. // num++;
  14. // console.log(num);
  15. // },
  16. // function sub() {
  17. // num--;
  18. // console.log(num);
  19. // }
  20. // ]
  21. return {add,sub};
  22. }
  23. // var arr2 = fnx2();
  24. // arr2[0](10);
  25. // arr2[1](10);
  26. var arr2=fnx2()
  27. console.log(arr2);
  28. arr2.add()//1
  29. arr2.add()//2

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

  1. function student() {
  2. var students = ['张三', '李四', '王五'];
  3. var fn = {
  4. join: function (name) {
  5. students.push(name);
  6. console.log(students);
  7. },
  8. leave: function (name) {
  9. var idx = students.indexOf(name);
  10. students.splice(idx, 1);
  11. console.log(students);
  12. }
  13. }
  14. return fn;
  15. }
  16. var fn = student();
  17. fn.join('小明');
  18. fn.join('小红');
  19. fn.leave('张三');
  1. <script>
  2. var x=1,
  3. y=(z=0);
  4. y=add(x);
  5. function add(n){
  6. n=n+3;
  7. return n;
  8. return n=n+3;
  9. }
  10. z=add(x);
  11. console.log(x,y,z)
  12. /*
  13. AO={
  14. n->undefined->1->n=n+3=4
  15. }
  16. 因为n是参数,函数运行时产生AO,n才初始化为undefined,把x的值1赋值给n,n=1,之后n=n+3等于4,函数运行完AO销毁,n就销毁了,之后再运行继续n的初始化,继续上述流程
  17. */
  18. </script>