首页 > 代码库 > 《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)函数表达式