JS之函数表达式

  度过一个愉快短暂的周末,又能够开始学习了!我爱学习,学习令人进步。今天学习函数表达式,着重学习下闭包函数。html

函数表达式前端

   能够在定义的函数声明以前调用它,可是不能在定义函数表达式以前调用它 c#

/**
 * 理解函数声明和函数表达式的区别,学习拉姆达(Lambda)表达式
 */
functionName(a);
aFuncton(a);//错误 function fuctionName(arg){};//函数声明 var aFunction=function (arg) {};//函数表达式(匿名函数) /* 函数声明:在执行代码以前会先读取函数声明,函数声明能够放在调用它的语句后面。
 Lambda表达式:建立匿名函数的一种方法,=>来表示
 运算符右边的表达式对运算符左边指定的参数执行操做
*/
var x=3,
   fun= 

x=>{returnx*x;};//lambda表达式

递归:在函数内部调用本身数组

  

/**
 * 借用arguments.callee和使用函数命名表达式实现递归
 */
//递归函数
function factorial(num){
    if(num<=1){ return 1; }else{ return num*factorial(num-1); } }; var anotherFactorial=factorial; factorial=null; alert(anotherFactorial(4));//出错,factorial值发生变化。 //解决方案:1.非严格模式下 function factorial(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); } }; //2.命名函数表达式 var factorial=(function f(num){ if(num<=1){ return 1; }else { return num * f(num - 1); } });

 

 闭包:可以访问另外一个函数做用域中的变量的函数。闭包

  做用域链:本质上是一个指向变量对象的指针列表函数

    建立函数时,会建立一个预先包含全局变量对象的的做用域链,这个做用域链被保存在内部的[[Scope]]属性中,调用函数时建立一个执行环境,而后复制[[Scope]]属性中的对象构建起执行环境的做用域链,而后有一个函数的活动对象被建立并推入执行环境做用域链的前端。学习

   在另外一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的做用域链中   this

function createComparisonFunction(propertyName) {
    return function(object1,object2){ var value1=object1[propertyName]; var value2=object2[propertyName]; if(value1<value2){return -1;} else if(value1>value2){return 1;} else{return 0;} }; } //建立函数 var compareNames=createComparisonFunction('name'); //调用函数 var result=compareNames({name:'赵云'},{name:'马超'}); //解除对匿名函数的引用,以便释放内存 compareNames=null;

  做用域链能够想象成一个列表,里面的函数建立时候内部建立它,这个列表中,最上面的spa

  上面的例子中,有两个做用域链,createComparisonFunction和匿名函数function(object1,object2)的做用域链分别是A和B。匿名函数从compareName()被返回后,B包含全局变量对象、createComparisonFunction函数的活动对象和匿名函数的活动对象的引用,createComparisonFunction函数执行完毕A被销毁,可是它的活动对象被B引用,虽然这样能够在全局环境中访问外部这个函数的变量了,但这个外部函数的活动对象已然存在。因此调用函数结束后要解除对匿名函数的引用。设计

    

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

    上面的例子中,最后result数组中每一个值都是10! 由于i是a函数活动对象中的变量,每一个内部函数做用域链中都有a的活动对象,因此引用的是同一个i,a函数返回后i=10。

解决方案:使用当即执行函数

 1 function a() {
 2     var result = []; 3 for (var i = 0; i < 10; i++) { 4 result[i] = function (num) { 5 return function () { 6 return num; 7  } 8  } 9 return result; 10  } 11 }

 

  在做用域中声明的变量,可能会被其余人不当心用同名的变量给覆盖掉,做用域链的特性,用匿名函数做为一个容器,容器内部能够访问外部的变量,而外部环境不能访问容器内部的变量,因此( function(){…} )()内部定义的变量不会和外部的变量发生冲突,至关于命名空间。

  闭包中使用this对象

    this对象是在运行时基于函数的执行环境绑定的:全局函数,this等于window,而当函数被最为某个对象的方法调用时,this就是那个对象。因为匿名环境具备全局性,它的this一般指向window.

 1 var name='Window';
 2 var  object={ 3 name:'object', 4 getName:function(){ 5 return function () { 6 return this.name 7  } 8  } 9 };; 10 console.log(object.getName()) //Window

  例子中getName方返回一个匿名函数,这个匿名函数返回this.name,调用内部匿名函数的时候,你不函数在搜索this和arguments两个变量时,只会搜索到活动对象为止。

解决方案:

var name='Window';
var  object={ name:'object', getName:function(){ var that=this; return function () { return that.name; } } }; console.log(object.getName());

 

  闭包函数会致使内存泄露,在垃圾清理的引用计数模式中,若是有闭包函数做用域链中有html元素,则该元素的引用至少一直是1,所以它所占用的内存不会被回收,所以要吧该元素的赋值变量设为null;

    模仿块级做用域:

(function(){})();//把函数声明转为函数表达式

当即调用了一个匿名函数

在一个由不少开发人员共同参与的大型应用程序中,过多的全局变量和函数容易致使命名冲突,经过建立私有做用域解决。

    私有变量

  任何函数中定义的变量,能够认为是私有变量。包括函数的参数,局部变量和函数内部定义跌其它函数。

访问私有变量方法:1构造函数中建立闭包

  静态私有变量:利用原型。

 

重点:模块模式

  对象字面量:实际是单例(只有一个实例的对象)。模块模式就是为单例建立私有变量和特权方法。

  

 1 var singleton=function(){
 2     //私有变量和私有函数
 3     var privateVaribale=10; 4 function privateFunction(){ 5 return false; 6  } 7 return{ 8 publicProperty:true; 9  publicMethod:funciont(){ 10 privateVaribale++; 11 return privateFunction(); 12  } 13  }; 14 }();

  这个模块模式使用了一个返回对象的匿名函数。在这个匿名函数内部,首先定义了私有变量和函数,有一个对象字面量做为函数的值返回,所以它的公有方法有权访问私有变量和函数。从本质上来讲,这个对象字面量定义的是单例的公共接口。这种模式在须要对单例进行某些初始化,同时又须要维护其私有变量时是很是有用的。

  模块模式用来设计一个加载器什么的颇有用,专门写一篇来分析。

相关文章
相关标签/搜索