zoukankan      html  css  js  c++  java
  • JS之函数表达式

      度过一个愉快短暂的周末,又可以开始学习了!我爱学习,学习使人进步。今天学习函数表达式,着重学习下闭包函数。

    函数表达式

       可以在定义的函数声明之前调用它,但是不能在定义函数表达式之前调用它 

    /**
     * 理解函数声明和函数表达式的区别,学习拉姆达(Lambda)表达式
     */
    functionName(a);
    aFuncton(a);//错误 function fuctionName(arg){};//函数声明 var aFunction=function (arg) {};//函数表达式(匿名函数) /* 函数声明:在执行代码之前会先读取函数声明,函数声明可以放在调用它的语句后面。
     Lambda表达式:创建匿名函数的一种方法,=>来表示
     运算符右边的表达式对运算符左边指定的参数执行操作
    */
    var x=3,
       fun=x=>{return x*x;};//lambda表达式

    递归:在函数内部调用自己

      

    /**
     * 借用arguments.callee和使用函数命名表达式实现递归
     */
    //递归函数
    function factorial(num){
        if(num<=1){
            return 1;
        }else{
            return num*factorial(num-1);
        }
    };
    var anotherFactorial=factorial;
    factorial=null;
    alert(anotherFactorial(4));//出错,factorial值发生变化。
    //解决方案:1.非严格模式下
    function factorial(num){
        if(num<=1){
            return 1;
        }else{
            return num*arguments.callee(num-1);
        }
    };
    //2.命名函数表达式
    var  factorial=(function f(num){
        if(num<=1){
            return 1;
        }else {
            return num * f(num - 1);
        }
    });

     闭包:能够访问另一个函数作用域中的变量的函数。

      作用域链:本质上是一个指向变量对象的指针列表

        创建函数时,会创建一个预先包含全局变量对象的的作用域链,这个作用域链被保存在内部的[[Scope]]属性中,调用函数时创建一个执行环境,然后复制[[Scope]]属性中的对象构建起执行环境的作用域链,然后有一个函数的活动对象被创建并推入执行环境作用域链的前端。

       在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中   

    function createComparisonFunction(propertyName) {
        return function(object1,object2){
            var value1=object1[propertyName];
            var value2=object2[propertyName];
            if(value1<value2){return -1;}
            else if(value1>value2){return 1;}
            else{return 0;}
        };
    }
    //创建函数
    var compareNames=createComparisonFunction('name');
    //调用函数
    var result=compareNames({name:'赵云'},{name:'马超'});
    //解除对匿名函数的引用,以便释放内存
    compareNames=null;

      作用域链可以想象成一个列表,里面的函数创建时候内部创建它,这个列表中,最上面的

      上面的例子中,有两个作用域链,createComparisonFunction和匿名函数function(object1,object2)的作用域链分别是A和B。匿名函数从compareName()被返回后,B包含全局变量对象、createComparisonFunction函数的活动对象和匿名函数的活动对象的引用,createComparisonFunction函数执行完毕A被销毁,但是它的活动对象被B引用,虽然这样可以在全局环境中访问外部这个函数的变量了,但这个外部函数的活动对象已然存在。所以调用函数结束后要解除对匿名函数的引用。

        

    function a(){
         var result=[];
        for (var i=0;i<10;i++){
            result[i]=function ()
            { return i;};
            }
    }

        上面的例子中,最后result数组中每个值都是10! 因为i是a函数活动对象中的变量,每个内部函数作用域链中都有a的活动对象,所以引用的是同一个i,a函数返回后i=10。

    解决方案:使用立即执行函数

     1 function a() {
     2     var result = [];
     3     for (var i = 0; i < 10; i++) {
     4         result[i] = function (num) {
     5             return function () {
     6                 return num;
     7             }
     8         }
     9         return result;
    10     }
    11 }

      在作用域中声明的变量,可能会被其他人不小心用同名的变量给覆盖掉,作用域链的特性,用匿名函数作为一个容器,容器内部可以访问外部的变量,而外部环境不能访问容器内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,相当于命名空间。

      闭包中使用this对象

        this对象是在运行时基于函数的执行环境绑定的:全局函数,this等于window,而当函数被最为某个对象的方法调用时,this就是那个对象。由于匿名环境具有全局性,它的this通常指向window.

     1 var name='Window';
     2 var  object={
     3     name:'object',
     4     getName:function(){
     5         return function () {
     6             return this.name
     7         }
     8     }
     9 };;
    10 console.log(object.getName()) //Window

      例子中getName方返回一个匿名函数,这个匿名函数返回this.name,调用内部匿名函数的时候,你不函数在搜索this和arguments两个变量时,只会搜索到活动对象为止。

    解决方案:

    var name='Window';
    var  object={
        name:'object',
        getName:function(){
            var that=this;
            return function () {
                return that.name;
            }
        }
    };
    console.log(object.getName());

      闭包函数会导致内存泄露,在垃圾清理的引用计数模式中,如果有闭包函数作用域链中有html元素,则该元素的引用至少一直是1,因此它所占用的内存不会被回收,因此要吧该元素的赋值变量设为null;

        模仿块级作用域:

    (function(){})();//把函数声明转为函数表达式

    立即调用了一个匿名函数

    在一个由很多开发人员共同参与的大型应用程序中,过多的全局变量和函数容易导致命名冲突,通过创建私有作用域解决。

        私有变量

      任何函数中定义的变量,可以认为是私有变量。包括函数的参数,局部变量和函数内部定义跌其它函数。

    访问私有变量方法:1构造函数中创建闭包

      静态私有变量:利用原型。

    重点:模块模式

      对象字面量:实际是单例(只有一个实例的对象)。模块模式就是为单例创建私有变量和特权方法。

      

     1 var singleton=function(){
     2     //私有变量和私有函数
     3     var privateVaribale=10;
     4     function privateFunction(){
     5         return false;
     6     }
     7     return{
     8         publicProperty:true;
     9         publicMethod:funciont(){
    10             privateVaribale++;
    11             return privateFunction();
    12         }
    13     };
    14 }();

      这个模块模式使用了一个返回对象的匿名函数。在这个匿名函数内部,首先定义了私有变量和函数,有一个对象字面量作为函数的值返回,因此它的公有方法有权访问私有变量和函数。从本质上来说,这个对象字面量定义的是单例的公共接口。这种模式在需要对单例进行某些初始化,同时又需要维护其私有变量时是非常有用的。

      模块模式用来设计一个加载器什么的很有用,专门写一篇来分析。

      

      

  • 相关阅读:
    mybatis配置
    mybatis 多表查询 与配置
    Maven中资源导出问题解决方案--pom.xml配置
    【macOS】Mac App Store 无法 更新/下载
    【macOS】删除 Mac 上的 Office 许可证文件
    【前端】JavaScript学习笔记(一)——快速入门
    【前端】CSS3学习笔记(五)——定位
    【前端】CSS3学习笔记(四)——浮动
    【前端】CSS3学习笔记(三)——盒子模型
    【macOS】清除Finder 「前往」(⌘
  • 原文地址:https://www.cnblogs.com/hai233/p/5969876.html
Copyright © 2011-2022 走看看