《JavaScript高级程序设计(第二版)》学习函数表达式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《JavaScript高级程序设计(第二版)》学习函数表达式相关的知识,希望对你有一定的参考价值。

声明:这类属于学习笔记,主要是摘录书中内容,比较少的整理。内容经常是跳跃的,建议您阅读书本,收益更大。


 定义函数的方式有2种,第一种是函数声明,另一种是函数表达式

函数声明会提升,就是javascript引擎先什么都不干,先把函数声明的代码解析一下,那么你是在此之前先用还是后用就无所谓了;但是表达式就没有这种特点,必须在函数表达式之后调用才不会出错。

//这个是可以的
sayhi();
function sayhi(){
    alert("hi");
}

//这种是不行的
sayhi();
var sayhi=function(){
    alert("hi");
};

 

关于递归:递归因为函数名可能变化,因此一般不会使用函数名,而是使用arguments.collee(n-1)类似这样的方法,但是在严格模式下,是不能获取arguments的,因此可以这么做

//在严格模式下arguments.callee无法通过脚本访问
//可以使用如下方法来代替使用
var fac=(function f(num){
    if(num<=1){
        return 1;
    }else{
        return num*f(num-1);
    }
});

console.log(fac(5));

 

闭包

有权访问另一个函数作用域中的变量的函数
创建闭包的常见方式使用嵌套函数

当函数第一次被调用时,会创建一个执行环境以及相应的作用域链,并把作用域链赋值给一个特殊的内部属性[[scope]]。然后使用this,arguments和其他命名函数的值来初始化函数的活动对象。但是外部函数的活动对象处于第二位,这样一直到全局执行环境。

在后台的每个执行环境都有一个表示变量的对象——变量对象。全局环境下的变量对象始终存在,而函数内的局部环境的变量对象,在函数执行结束后就消失了。作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

然而闭包靠内部定义的函数会将包含函数(外部函数)的活动对象添加到它的作用域链中。当外部函数(不是全局函数的话)执行结束,其执行环境的作用域链会销毁,但活动对象不会回收。

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,过多使用闭包可能导致内存占用过多。

 

其次
作用域链的配置机制引起一个闭包的副作用:
只能取得包含函数中任何变量的最后一个值。

function createFunc(){
    var result=new Array();

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

// 得到的函数数组里,i全都10

因为每个函数的作用域链中都保存着外部函数的活动对象,所以他们引用的是同一个变量i,当函数返回result,i的值都是10.

对此我们可以用一种办法强制让闭包符合我们的预期

function create(){
    var result=new Array();

    for(var i=0; i<10; i++){
        result[i]=function(num){
            return function(){
                return num;
            };
        }(i);//立即执行匿名函数并将结果给result
    }
    return result;
}

console.log(create());

闭包里一个经常容易造成问题的是this

匿名函数的执行环境具有全局性,因此this通常是指向window。但因为闭包编写的方式不同,这一点可能会有所不同。

var name="the window";

var obj={
    name:"My object",
    getNameFunc:function(){
        return function(){
            return this.name;
        };
    }
};

console.log(obj.getNameFunc()()); //the window
var name="the window";

var obj={
    name:"My object",
    getNameFunc:function(){
        var that=this
        return function(){
            return that.name;
        };
    }
};

console.log(obj.getNameFunc()()); //my object

在下面这几种特殊情况下this也可能会意外改变

    var name="the window";

    var obj={
        name:"my object",
        getNameFunc:function(){
            return this.name;
        }
    };

    console.log(obj.getNameFunc()); //the object
    var aa=(obj.getNameFunc)(); //the object
    var bb=(obj.getNameFunc=obj.getNameFunc)(); //the window
    console.log(aa+"  "+bb);

    //第一行代码和平常一样调用了对象的方法
    //第二行代码使用了立即执行
    //第三行先是执行了赋值语句,然后调用赋值结果。因为赋值表达式是函数本身
    //所以this不能得到维持,结果就返回了this.window

 

以上是关于《JavaScript高级程序设计(第二版)》学习函数表达式的主要内容,如果未能解决你的问题,请参考以下文章

《javascript高级程序设计(第二版)》学习原型与继承

《JavaScript高级程序设计(第二版)》学习函数表达式

《JavaScript高级程序设计 第二版》理解对象

细读《从问题到程序(第二版)》第一章学习总结

《JavaScript高级程序设计》啥时候出版

JavaScript学习