javaScript Function(函数) 闭包 匿名函数 this对象

1. Function

函数接受的参数类型、个数没有限定。参数在内部是用数组arguments来存储的。因此函数没有重载。可以提供arguments【i】来表示传入的参数

4.1创建

使用函数声明和函数表达式创建,也可以使用Function()构造函数

Function sum(num1,num2){

函数声明

}

Var sum = function(num1,num2){

       函数表达式

}

解析器会率先读取函数声明,并使其在执行任何代码之前可用;因为在代码执行之前,解析器就已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境,js引擎在第一遍会声明函数并将它们放到源代码树的顶部。函数表达式须等到解析器执行到它所在代码行,才会真正被解析。

4.2函数内部属性

Arguments指代参数

Callee:arguments.callee指代拥有这个arguments对象的函数。在递归调用时,非常有用。

Caller:保存着调用当前函数的函数的引用

Function outer(){

       Inner();

}

Function inner(){

       Alert(inner.caller);//警告框中显示outer()函数的源代码,等价于arguments.callee.caller

}

This:this引用的是函数据以执行的环境对象。

4.3 call()和apply()扩大函数赖以运行的作用域

每个函数都包含这两个非继承而来的方法。这两个方法用途都是在特定的作用域里调用函数,实际上是设置函数体内的this值。

Apply()接受2个参数,一个是其中函数运行的作用域,另一个是参数数组

Call()接受多个参数,一个是其中函数运行的作用域,其他是传递给函数的参数必须逐个列举出来

Window.color = “red”;

Var o = {

       Color:”blue”

};

Function sayColor(){

       Alert(this.color);

}

sayColor(); //red

sayColor.call(window); //red

sayColor.call(this); //red

sayColor(o);  //blue

4.4java与js创建函数

Java是:修饰符  返回类型  函数名(参数类型 参数名){

              函数体

}

Js是:函数声明和函数表达式

函数声明:function 函数名(参数名){

          函数体

}

函数表达式:var 函数名 = function(参数名){

              函数体

}

4.5匿名函数

在function后面没有跟函数名的函数称为匿名函数。例如:

function(){

                                          函数体

                                   }

1.6     闭包

4.6.1闭包作用域链

闭包是有权访问另一个函数作用域中变量的函数。因此任何函数都是闭包。当某函数第一次被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋值给一个特殊的内部属性即[[scope]]。然后使用this、arguments和其他命名参数的值来初始化函数的活动对象。

由此得出,js中所有函数都是闭包。

在全局环境中定义compare函数:

function compare(value1,value2){

                            if(value1 < value2){

                                   return -1;

                            }else if(value1 > value2){

                                   return 1;

                            }else{

                                   return 0;

                            }

                     }

                     var result = compare(5,10);

在创建compare()函数时,会创建一个预先包含全局变量对象的作用域链,并保存在[[scope]]。当调用compare()函数时,会创建一个包含this、arguments、value1、value2的活动对象。此刻compare()执行环境的作用域链(scope)是[[scope]]+活动对象。Scope可以看出数组,活动对象在最前面,[[scope]]在后面。

函数在创建时获得函数的[[scope]],通过该属性访问到所有父上文的变量。同一个父上下文中创建的闭包是共用一个[[scope]],其中一个闭包对[[scope]]修改会影响到其他闭包

每个执行环境都有一个表示变量的对象,全局环境的变量对象一直存在,局部函数的执行环境也有变量对象,但只在函数执行的过程中存在(闭包除外)。

4.6.2闭包中的变量

当你弄清作用域链,你对闭包中变量的取值将会很清楚。

在这里,我将再举一个例子,说明下作用域链。

var x = 10;

                     function foo(){

                            var y = 20;

                            function bar(){

                                   var z = 30;

                                   alert(x+y+z);

                            }

                            bar();

                     }

                     foo();

在创建foo函数时,此时会创建一个包含x为10的全局作用域。

同一个父上下文中创建的闭包是共用一个[[scope]],其中一个闭包对[[scope]]修改会影响到其他闭包。

function fee(){

                            var data = [];

                            for(var k=0;k<3;k++){

                                   data[k] = function(){

                                          return k

                                   }

                            }

                            return data;

                     }

                     console.log(fee());//返回值如下

                     /*[function (){

                                          return k

                                   }, function (){

                                          return k

                                   }, function (){

                                          return k

                                   }]*/

 由此可见,返回的是k值,而这个k存在父上下文中,所以data里存相同的数值。

当将data[k] = function(){return k}改为

 data[k] = function(num){

       return function(){return num}

}(k);此时data存不同的值。              

4.6.2关于this对象

在全局函数中,this等于window,而当函数被某个对象调用时,this指代那个对象。但是匿名函数不一样,他的执行环境具有全局性,其this指代window。

var name = "lily";

                                   var object = {

                                          name : "my name",

                                          getName : function(){

                                                 alert(this.name); //my name

                                                 return function(){

                                                        return this.name; //lily

                                                 }

                                          }

                                   };

                                   alert(object.getName()()); //my name,lily

在每个函数被调用时其活动对象都会自动获取this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,不可能去访问父上下文。

看下面的例子

var name = "lily";

                                   var person = {

                                          name : "my name",

                                          getName : function(){

                                                 var that = this;

                                                 return function(){

                                                        return this.name; //my name                                                                                         }

                                          }

                                   };

                                   alert(person.getName()()); //my name

此刻就可以让闭包访问person对象了。

4.6.2模仿块级作用域

Js没有块级作用域,这个跟其他面向对象语言不一样。

例如: for(var i = 0 ; i< 3; i++){

    alert(i);

}

alert(i);  //3

用块级作用域(通常称为私有作用域)的匿名函数的语法如下:

(function(){

       //这里是块级作用域。这里的变量一旦等到该函数执行完就被销毁。

})();

function(){}();会报错,这是因为js会将function关键字当做函数声明的开始,而函数声明后面不能加()。而函数表达式后面可以跟(),例如:

var lulu = function(){alert(895);}();

只要是临时需要变量,可以使用私有作用域。

例如:         function out(count){

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

                                   alert(i);

                            })();

                            alert(i);//此时会报错,i是一个没有声明的变量。

                     }

                     out(3);

变量i只能在循环中使用,使用后被销毁。而在私有作用域中能过访问父上下文的变量,因为匿名函数是一个闭包。

这种技术经常用在函数外部,从而限制全局作用域中添加过多的变量和函数。减少闭包占用内存的问题。

原文地址:https://www.cnblogs.com/qduanlu/p/2818109.html