• JS匿名函数


    函数声明与函数表达式的区别:(2点)

    前者会在代码执行以前被加载到作用域中,而后者则是代码被执行到那一行时才会有定义。

    函数声明会给函数指定一个名字,而函数表达式则是创建一个匿名函数,然后将这个匿名函数赋给一个变量。

    递归

    arguments.callee是一个指向正在执行的函数的指针。

    1 //经典的递归阶乘函数
    2 function factorial(num) {
    3     if (num<=1) {
    4         return 1;
    5     }else {
    6         return num * arguments.callee(num-1);
    7     }
    8 }
    9 debug(factorial(4));

    闭包

    闭包的概念很简单:一个闭包是一个函数及定义它的环境的组合。

    例如,在一个函数A内部定义其他函数B时,就创建了闭包。闭包有权访问包含函数(A)内部的所有变量。

     1 //返回一个函数
     2 function createComparison(propertyName) {
     3     return function(obj1, obj2) {
     4         var value1 = obj1[propertyName],
     5             value2 = obj2[propertyName];
     6         //return value1 - value2;
     7         if (value1 > value2) {
     8             return 1;
     9         }else if(value1 < value2) {
    10             return -1;
    11         }else {
    12             return 0;
    13         }
    14     }
    15 }
    16 var compareName = createComparison('name');
    17 debug(compareName({name:'mack'},{name:'an'}));        //1
    18 compareName = null;        //解除对匿名函数的引用,释放内存

    由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存

    1. 闭包与变量

    a. 当某个函数第一次被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋给一个特殊的内部属性([[scope]])。

    b. 然后使用this、arguments和其他命名参数的值来初始化函数的活动对象。在作用域链中外部函数的活动对象处于第二位……

    c. 在函数执行过程中,为读取和写入变量的值,需要在作用域链中查找变量。

     1 闭包只能取得包含函数中任何变量的最后一个值:
     2 function createFunctions() {
     3     var result = new Array();
     4     for (var i=0; i<10; i++) {
     5         result[i] = function() {
     6             return i;
     7         }
     8     }
     9     return result;
    10 }
    11 //funcs 存储的是10个匿名函数
    12 var funcs = createFunctions();
    13 //debug(funcs);
    14 //输出数组中的元素值(全部都是10)
    15 for (var i=0; i < funcs.length; i++) {
    16     debug(funcs[i]());
    17 };
    18 更改写法:
    19 function createFunctions() {
    20     var result = new Array();
    21     for (var i=0; i<10; i++) {
    22         //把i的当前值赋值给局部变量
    23         result[i] = function(num) {
    24             return function() {
    25                 return num;
    26             }
    27         }(i);
    28     }
    29     return result;
    30 }
    31 //funcs 存储的是10个匿名函数
    32 var funcs = createFunctions();
    33 //输出数组中的元素值(0.1..9)
    34 for (var i=0; i < funcs.length; i++) {
    35     debug(funcs[i]());
    36 }

          2.关于this对象

    关于this对象(arguments存在同样的问题)

    this对象是在运行时基于函数的执行环境绑定的,但匿名函数的执行环境具有全局性,因此this对象指向window.

     1 var name = 'The Window';
     2 var obj = {
     3     name: 'mackxu',
     4     getName: function() {
     5         return function() {
     6             return this.name;
     7         }
     8     }
     9 };
    10 debug(obj.getName()());        //The Window
    11 //把外部作用域的this对象保存在一个闭包能够访问到的变量中
    12 var name = 'The Window';
    13 var obj = {
    14     name: 'mackxu',
    15     getName: function() {
    16         var that = this;
    17         return function() {
    18             return that.name;
    19         }
    20     }
    21 };
    22 debug(obj.getName()());        //mackxu

        3.IE中的内存泄露

    如果闭包作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁

     1 function assignHandler() {
     2         //无法减少对element 的引用数
     3 var element = document.getElementById(‘#id’);
     4         element.onclick = function() {
     5     debug(element.id);
     6 };
     7 }
     8 解决办法:
     9 function assignHandler() {
    10 var element = document.getElementById(‘#id’);
    11 var id = element.id;
    12         element.onclick = function() {
    13     debug(id);
    14 };
    15 element = null;
    16 }

    模仿块级作用域

    Js没有块级作用域的概念

     1 Js没有块级作用域的概念
     2 function output() {
     3     //在for中定义的变量i,可以在for外面访问
     4     for (var i=0; i<10; i++) {
     5         //...
     6     }
     7     debug(i);        //output:10
     8 }
     9 output();
    10 私有作用域:用作块级作用域的匿名函数,函数被执行后,里面的变量会马上销毁
    11 (function(){
    12     //这里是块级作用域
    13 })();
    14 改写上一个例子:
    15 function output() {
    16     //匿名函数被执行后,i变量将被销毁
    17     (function(){
    18         for (var i=0; i<10; i++) {
    19             //...
    20         }
    21     })();
    22     debug(i);        //error
    23 }

    这种技术经常在全局作用域中被用在函数外面,限制向全局作用中添加过多的变量和函数。

    私有变量

    任何在函数中定义的变量,可认为是私有变量,因为不能在函数外部访问这些变量。

    私有变量包括函数的参数、局部变量、在函数内定义的其他函数。

    特权方法:有权访问私有变量和私有函数的公有方法。

     1 function MyObject() {
     2     var private_var = 10;        //函数的私有变量
     3     //函数的私有方法
     4     function private_method() {
     5         return private_var;        //闭包能访问所在函数的所有属性
     6         //return 'private_method;
     7     }
     8     //特权方法[能访问私有变量、方法的公有方法]
     9     this.public_method = function() {
    10         private_var ++;
    11         return private_method();
    12     }
    13 }
    14 
    15 var obj = new MyObject();
    16 debug(obj.public_method());
    1. 静态私有变量[避免每个实例都要创建同一组新方法]

    在私有作用域中定义私有变量或函数,同样也可以创建特权方法

     1 (function() {
     2     //私有变量和函数
     3     //根据作用域链,private_var相对于特权方法(闭包)是外部函数的变量
     4     //其会变成一个静态的、由所有实例共享的属性[可以想象原型链继承父类的属性]
     5     var private_var = 10;
     6     function private_func() {
     7         return 'private function';
     8     }
     9     //没有被var声明,会自动添加到全局对象中
    10     MyObject = function() {};
    11     MyObject.prototype.public_method = function() {
    12         private_var ++;
    13         private_func();
    14         return 'OK';
    15     };
    16 })();
    17 //可以在私有作用域外,访问MyObject
    18 var obj = new MyObject();
    19 debug(obj.public_method());
    20 送上一个实例说明:
    21 (function() {
    22     var name = '';        //静态私有变量
    23     
    24     Person = function(value) {
    25         name = value;
    26     };
    27     Person.prototype.getName = function() {
    28         return name;
    29     };
    30     Person.prototype.setName = function(value) {
    31         name = value;
    32     };
    33 })();
    34 
    35 var p1 = new Person('mackxu');
    36 debug(p1.getName());        //mackxu
    37 var p2 = new Person('zhangsan');
    38 debug(p2.getName());        //zhangsan
    39 p2.setName('anan');
    40 debug(p1.getName());        //anan

    模块模式 

    JavaScript是以对象字面量的方式来创建单例对象的。

     1 //函数返回的是对象
     2 var singleton = function() {
     3     //私有变量和方法
     4     var private_var = 10;
     5     function private_func() {
     6         return 'private function';
     7     }
     8     
     9     //返回公有方法和属性
    10     return {
    11         public_var: 22,
    12         public_method: function() {
    13             //访问私有变量和函数
    14             private_var ++;
    15             return private_func();
    16         }
    17     };
    18 }();
    19 debug(singleton.public_method());

    这个模式在需要对单例进行某些初始化,同时又需要维护其私有变量时很有用。

    增强的模块模式

    单例必须是某种类型的实例

     1 function CustomType() {
     2     //...
     3 }
     4 //函数返回的是对象
     5 var singleton = function() {
     6     //私有变量和方法
     7     var private_var = 10;
     8     function private_func() {
     9         return 'private function';
    10     }
    11     
    12     //创建特定类型的对象,并返回
    13     var obj = new CustomType();
    14     //添加公有方法和属性
    15     obj.public_var = true;
    16     obj.public_method = function() {
    17         private_var++;
    18         return private_func();
    19     }
    20     return obj;
    21 }();
    22 
    23 debug(singleton.public_method());
    24 debug(singleton instanceof CustomType);        //true
  • 相关阅读:
    最长回文子串 leetcode
    leetcode Plus one
    n的阶乘末尾有几个0?
    求两数的最大公约数和最小公倍数
    汉诺塔
    求n的阶乘
    svn book
    求斐波那契数列第n项
    判断一个数是否是素数
    <C Traps and Pitfalls>笔记
  • 原文地址:https://www.cnblogs.com/mackxu/p/closure.html
Copyright © 2020-2023  润新知