首页 > 代码库 > 《JavaScript高级程序设计(第二版)》学习(5)函数表达式

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

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


 定义函数的方式有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高级程序设计(第二版)》学习(5)函数表达式