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;
    }();
  • 相关阅读:
    2、容器初探
    3、二叉树:先序,中序,后序循环遍历详解
    Hebbian Learning Rule
    论文笔记 Weakly-Supervised Spatial Context Networks
    在Caffe添加Python layer详细步骤
    论文笔记 Learning to Compare Image Patches via Convolutional Neural Networks
    Deconvolution 反卷积理解
    论文笔记 Feature Pyramid Networks for Object Detection
    Caffe2 初识
    论文笔记 Densely Connected Convolutional Networks
  • 原文地址:https://www.cnblogs.com/liuzhongyi1992/p/3473006.html
Copyright © 2011-2022 走看看