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

    一.定义函数

    定义函数的两种方式:函数声明和函数表达式

    1.函数声明

    function functionName(arg0,arg1,…){

        //函数体

    }

    ①name属性:访问函数的名字

    alert(funcitonName.name);//”functionName”

    ②函数声明提升

    在代码执行之前会先读取函数声明(解析器会率先读取函数声明)。所以函数声明可以放到调用它的语句后边

    2.函数表达式:创建函数再赋值给变量

    var functionName=function(arg0,arg1,…){

        //函数体

    };

    ①函数声明要求有名字,但函数表达式不需要。没有名字的函数表达式叫匿名函数

    ②没有函数声明提升,所以使用前先赋值

    sayName(); //出错

    var sayName=function(){

        alert(“liuzhongyi”);

    };

    ③在控制语句中应该使用函数表达式,而不是函数声明

    ④使用匿名函数可以将函数当做值来使用,将函数作为其他函数的返回值等

    二.递归

    递归函数:一个函数通过名字调用自身

    但使用函数名调用自身时,只要函数名变化,递归函数将出现问题

    ①使用arguments.callee来调用自身:是一个指针,指向正在执行的函数

    function myFunction(num){
        if(num<=1){
            return 1;
        }else{
            return num * arguments.callee(num-1);
        }
    }

    ②使用函数表达式

    var myFunction=(function f(num){
        if(num<1){
            return 1;
        }else{
            return num*f(num-1);
        }
    });

    即使将myFunction改名,f(num)依然能在函数内使用

    三.闭包

    闭包:有权访问另一个函数作用域中的变量 的函数

    创建闭包:在函数内部创建另一个函数

    1.闭包原理

    ①执行环境和作用域链

    QQ截图20131205235823

    作用域链本质是一个指向变量对象的指针列表,只引用但不实际包含变量对象

    当函数执行完毕后,执行环境,作用域链及局部变量对象就会销毁,内存中只保存全局作用域(全局变量对象)

    ②在一个函数内部定义的匿名函数将外部函数的活动对象(局部变量对象)添加到它的作用域链中

    这个匿名函数被返回后,它的作用域链被初始化为包含它自己的作用域,包含函数的作用域和全局作用域

    函数在执行完毕后,其活动对象也不会销毁,因为匿名函数的作用域链依然在引用这个活动对象

    解除匿名函数的引用,活动对象被销毁 myFunction=null;

    2.闭包与变量

    闭包只能取得包含函数中任何变量的最后一个值      //没看懂

    3.关于this对象

    this对象是与函数运行时的执行环境绑定的,全局函数中this等于window,当函数作为某个对象的方法调用时,this等于那个对象

    var name="window";
    var object={
        name:"object",
        getThis:function(){
            return function(){
                return this.name;
            };
        }
    };
    alert(object.getThis()); //"window" 因为this能够访问到全局变量中的name变量

    this不能指向自己吗??

    var name="window";
    var object={
        name:"object",
        getThis:function(){
            return this.name;
        }
    };
    (object.getThis=object.getThis)(); //"window"
    4.内存泄漏
    闭包的作用域链中保存着一个HTML元素,那么该元素将无法被销毁
    因为BOM,COM对象是以COM对象的形式实现的,采用的是引用计数的垃圾收集策略,由于闭包的存在,HTML元素的引用次数至少是1,所以不能被收回
    四.模仿块级作用域
    function outputNumbers(count){
        for(var i=0;i<count;i++){
            alert(i);
        }
    
    var i;
    alert(i); //依然计次
    }

    Java,C中i只会在for循环的语句块中有定义,循环一结束,变量i就会被销毁。但JS中没有块级作用域,i定义在outputNumbers()的活动对象里,而且会对后续的再次声明视而不见

    1.私有作用域:用匿名函数模仿块级作用域

    function关键字表示函数声明的开始,将函数声明转换成函数表达式,只要给它加上一对圆括号。函数表达式可以直接作为值来取代函数名。调用函数就是在后边加一对圆括号

    (function{
        //块级作用域
    })();

    匿名函数中定义的任何变量,都会在执行结束时被销毁

    function outputNumbers(count){
        (function(){
            for(var i=0;i<count;i++){
                alert(i);
            }
        })();
    alert(i); //出错
    }

    好处:

    ①私有作用域,每个开发人员都可以定义自己的变量,而不用担心扰乱全局作用域

    ②可以减少闭包占用的内存,因为没有指向匿名函数的引用,函数执行完作用域链就可以销毁

    2.私有变量

    所有对象属性都是公有的。(可以在外部访问对象属性)

    私有变量:函数的参数,局部变量,函数内部定义的其他函数。在函数外部不能访问这些变量

    公有方法:可以通过闭包来实现公有方法,而通过公有方法可以访问在包含作用域中定义的变量

    特权方法:有权访问私有变量的方法叫特权方法

    自定义类型的特权方法

    ①在构造函数中定义特权方法

    function Person(name){
        this.getName=function(){
            return this.name;
        };
        this.setName=function(value){
            this.name=value;
        };
    }
    var person1=new Person("liu");
    alert(person1.getName());// "liu"
    person1.setName("zhong");
    alert(person1.getName()); //"zhong"

    实现了在构造函数外部访问了私有变量name

    缺点:构造函数的弊端,每个实例都会创建同一组相同的方法

    ②静态私有变量

    (function(){
        var name="";
        Person=function(value){   //声明全局变量,使用函数表达式,因为函数声明只能创建局部函数
            name=value;
        };
        Person.prototype.getName=function(){
            return name;
        };
        Person.prototype.setName=function(){
            name=value;
        };
    })();
    
    var person1=new Person("liu");
    alert(person1.getName()); //"liu"
    person1.setName("zhong");
    alert(person1.getName());

    在一个函数上调用私有变量会影响所有实例,每个实例没有自己的私有变量

    单例的特权方法

    ①模块模式

    为单例(只有一个实例的对象)创建私有变量和特权方法

    当必须创建一个对象并以某些数据对其初始化,同时还要公开一些能够访问这些私有数据的方法,就可以使用模块模式

    var application=function(){
        //私有变量和函数    
        var components=new Array();
        //初始化
        components.push("liu");
        //公有方法
        return{
            getLength:function(){
                return components.length;    
            }
        }; 
    }();

    ②增强的模块模式

    单例必须是某种类型的实例,同时还必须添加某些属性和方法对其以增强的情况

    //application对象必须是BaseComponent的实例
    var application=function(){
        //私有变量和函数
        var components=new Array();
        //初始化
        components.push(new BaseComponent());
        //创建application的一个局部副本
        var app=new BaseComponent();
        //公共接口
        app.getLength=funtion(){
             return components.length;
        };
        //返回这个副本
        return app;
    }();
  • 相关阅读:
    BootStrap Table前台和后台分页对JSON格式的要求
    神奇的外部嵌套(使用ROW_NUMBER()查询带条件的时候提示列名无效)
    要想获取select的值,使用ng-modle,否则无法获取select 的值
    Angular使用操作事件指令ng-click传多个参数示例
    Jenins 邮件通知
    Jenkins 流水线(Pipeline)
    Jenkins Master-Slave 架构
    Jenins 参数化构建
    Jenkins 用户权限管理
    Jenkins 安装
  • 原文地址:https://www.cnblogs.com/liuzhongyi1992/p/3473006.html
Copyright © 2011-2022 走看看