JS 函数表达式

定义函数方式:

1.函数声明

  • 函数声明提升:执行代码前会先读取函数声明
  • name属性:可以访问函数名

2.函数表达式

  • 匿名函数(拉姆达函数)
  • name属性是空字符串

可以创建函数赋值给变量,也能把函数作为其他函数的值返回

一 递归

递归函数是在一个函数通过名字调用自身的情况下构成的

function factorial(num){
    if(num<=1){
        return 1;
    }
    else{
        return factorial(num-1);
    }
}

var another=factorial;
factorial=null;
alert(another(4));  //出错

由于调用时,factorial不是函数,会出错。解决方案:arguments.callee(一个指向正在执行的函数的指针)

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

二 闭包

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

创建方式:常见方式就是在一个函数内部创建另一个函数

function createComparison(propertyName){
    return function(object1,object2){
        var value1=object1[property];
        var value2=object2[property];
        if(value1<value2){
            return -1;
        }else if(value1>value2){
             return 1;
        }else{
             return 0;
        }
    }
}

内部函数访问了外部函数中的变量,是因为内部函数的作用域链中包含外部函数的作用域

  • 当某个函数被调用时,会创建一个执行环境和相应的作用域链。之后,使用arguments和其他命名参数的值来初始化函数的活动对象。

函数执行时,会在作用域链中查找变量

function compare(value1,value2){
    if(value1>value2){
        return -1;
    }
    else if(value1<value2){
        return 1;
    }
}
var result=compare(5,10);

compare()函数执行时的作用域链:

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

一般函数执行完,局部活动对象会被销毁。但闭包不同。

  • 在createComparison()函数中,匿名函数会将包含函数的活动对象添加到它的作用域链中。
  • 在匿名函数从外部函数被返回后,它的作用域链被初始化为包含外部函数的活动对象和全局变量对象
  • 外部函数执行完后,其活动对象也不会销毁,因为匿名函数的作用域链仍然在引用这个活动对象(作用域链会被销毁,但活动对象仍会留在内存中)
var compareNames=createComparison("name");
var result=compareNames({name:"Nicholas"},{name:"Greg"});
//解除对匿名函数的引用(以便释放内存)
compareNames=null;

调用compareNames()过程中的作用域链:

2.1 闭包与变量

作用域链引出一个缺点:闭包只能取得包含函数中任何变量的最后一个值。(闭包保存的是整个变量对象,而不是某个特殊的值)

2.2 关于this对象

  • 匿名函数的执行环境具有全局性,其this对象指向window

几种情况下,this值可能会改变

var name="the window";
var object={
    name:"My object",
    getName:function(){
        return this.name;
    }
}

object.getName();   //My object
(object.getName)();  //My object
(object.getName=object.getName)();   //the window

相当于定义了一个object.getName的变量

(object.getName=function(){
    return this.name;
})()
//立即执行函数内部的this对象非严格模式下指向window

三 模仿块级作用域

  • JS没有块级作用域的概念
function outputNumber(count){
    for(var i=0;i<count;i++){
        alert(i);
    }
    var i;   //重新声明变量
    alert(i);    //计数
}
//无视后续声明

匿名函数可以模仿块级作用域避免以上问题

  • 用作块级作用域的匿名函数的语法
(function(){
    //块级作用域
})();
//定义了一个匿名函数,并立即调用
function(){
   //块级作用域
}();  //error

JS将function关键字当作一个函数声明的开始,而函数声明后不能跟括号。

function putputNumbers(count){
    (function(){
        for(var i=0;i<count;i++){
            alert(i);
        }
    })();
}

这种方法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链。

四 私有变量

私有变量:任何在函数中定义的变量,都可以认为是私有变量。

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

公有方法:在函数内部创建一个闭包,那么闭包通过自己的作用域链可以访问私有变量。利用这一点可以创建用于访问私有变量的公有方法。

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

在对象上创建特权方法的方式:

  • 在构造函数中定义特权方法
function(){
    //私有变量和私有函数
    var privateVariable=10;
    function privateFunction(){
        return false;
    }
    //特权方法
    this.publicMethod=function(){
        privateVariable++;
        return privateFunction;
    }
}

 利用私有和特权成员,可以隐藏不该被直接修改的数据

function Person(name){
    this.getName=function(){
        return name;
    };
    this.setName=function(){
        name=value;
    }
}

var person=new Person("Nicholas");
alert(person.getName());   //Nicholas
person.setName("Greg");
alert(person.getName());   //Greg

在构造函数中定义特权方法的缺点:必须使用构造函数模式达到这个目的。而对构造函数模式,,针对每个实例都会创建同样一组新方法。

使用静态私有变量可以避免该问题

4.1 静态私有变量

  • 通过在私有作用域定义私有变量或函数,创建特权方法
(function(){
    //私有变量和私有函数
    var privateVariable=10;
    function privateFunction(){
        return false;
    }
    //构造函数
    MyObject=function(){     //全局变量
    };
    //特权方法
    MyObject.prototype.publicMethod=function(){
        privateVariable++;
        return privateFunction();
    }
})();

与在构造函数中定义特权方法的主要区别:私有变量和函数是由实例共享的。由于特权方法是在原型上定义的,因此所有实例都使用同一个函数。这个特权函数,作为一个闭包,总是保存着对包含作用域的引用。

4.2 模块模式

单例:只有一个实例的对象

模块模式:为单例创建私有变量和特权方法。

  • JS一般以对象字面量的方法创建单例对象
var singleton={
    name:value,
    method:function(){
        
    }
}
  • 模块模式通过为单例添加私有变量和特权方法能够使其得到增强
var singleton=function(){
    //私有变量和私有函数
    var privateVariable=10;
    function privateVariable(){
        return false;
    }
    //特权方法
    return{           //将一个对象字面量作为函数的值返回
        publicProperty:true,
        piblicMethod:function(){
            privateVariable++;
            return privateFunction();
        }
    }
}

本质上:上面对象字面量定义的是单例的公共接口

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值