zoukankan      html  css  js  c++  java
  • 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只能在循环中使用,使用后被销毁。而在私有作用域中能过访问父上下文的变量,因为匿名函数是一个闭包。

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

  • 相关阅读:
    aspx页面,中文乱码解决方案
    使用JSP体验微信公众平台开发模式
    使用微信公众平台“编辑模式”的过程记录
    JAVA刷新网站IP访问量的技术探讨
    301. Remove Invalid Parentheses
    Dungeon Game
    刷题关键点总结-动态规划
    刷题关键点总结-单调栈、单调队列
    coin change
    常用vim命令
  • 原文地址:https://www.cnblogs.com/qduanlu/p/2818109.html
Copyright © 2011-2022 走看看