• 函数


    一、函数简介

      JavaScript中的函数是一段代码,被定义一次,但是可以调用或执行多次。函数定义的时候会包含一个函数形参的标识符列表,这些参数在函数内部像局部变量一样工作。函数调用时会为形参提供实参的值。函数调用时还有一个值,就是本次调用的上下文,就是this关键字指向的值。

      函数是对象,我们可以把它赋值给变量或者作为函数的参数。此外,我们还可以给他设置属性和方法。

    二、函数定义

      1、函数声明语句 

    1 function x(a,b){
    2   return a+b;
    3 }

      2、函数定义表达式   

    1 var x = function (a,b) {
    2   return a + b;
    3 }
    4 //自調用函數
    5 var y = (function (a, b) {
    6   return a + b;
    7 }(1, 2));
    8 console.log(y);//3

      没有return语句的函数的返回值时undefined;同时函数可以嵌套在另个函数里面,内部函数可以读取外部函数的局部变量。

    三、函数调用的方法

      1、作为函数

    1 //函数调用
    2 function X(){
    3     return 0;
    4 }
    5 var x=X();//0

      函数调用的this指向全局对象,严格模式下指向undefined,如果该函数有嵌套函数,嵌套函数的this也指向全局对象(undefined)。

      2、方法调用 

     1 function X(){
     2     var self=this;
     3     function myfun(){
     4         console.log(self===o);//true
     5         console.log(this===global);//true
     6     }
     7     myfun();
     8     return 0;
     9 }
    10 var o={};
    11 o.m=X;
    12 //方法调用
    13 var x=o.m();//x

      方法调用的this指向调用方法的对象。内部函数要访问外部函数的this,需要将this保存在一个对象中。

      3、构造函数调用

      调用构造函数通常使用new关键字,构造函数的调用对象(this)就是这个新创建的。使用new 关键字调用构造函数时,先创建一个新的空对象,对象的原型指向构造函数的prototype属性,然后初始化这个对象并返回。

    如果构造函数没有return或者有return但是返回的是一个原始值或者没有指定返回值,则表达式的值是这个新建的对象,如果return返回的是一个对象,则表达式的值是这个对象。

      4、间接调用

      使用Function.call()和Function.apply()间接调用函数,第一个参数指定调用方法的上下文(this),后面的参数指定调用方法需要的参数,call()中参数作为方法的实参,apply的参数以数组的形式传给方法的实参。

    1 function x(x){
    2    console.log(x);    
    3 }
    4 x.call(null,'hello');//hello
    5 x.apply(this,['world']);//world

    四、函数的形参和实参

      函数定义的时候传入的参数是形参,函数调用的时候传入的参数是实参,形参的引用指向实参。

      JavaScript中函数调用时如果实参多余形参或自动省略,实参少于形参时用undefined填补。

        利用不够的形参将使用undefined,我们可以实现一个参数可选的函数,可选的参数应该放在最后,当我们不给他传入值时应该使用默认值。  

    1 //可选参数的函数
    2 function x(a,b){
    3     if(a===undefined) a=10;
    4     b=b||1;
    5     return a+b;
    6 }
    7 console.log(x()); //11

      arguments是指向实参对象的引用,实参对象是一个类数组对象。可以同下标的形式访问实参(第一个实参用argumens[0],...),也可以实现可变长形参的函数。

      比较任意个数的中的最大值; 

     1 //可选参数的函数
     2 function x(/*...*/){
     3    var max=arguments[0];
     4    for(var i=0;i<arguments.length;i++){
     5         if(max<arguments[i])
     6             max=arguments[i];
     7    }
     8    return max;
     9 }
    10 console.log(x(1,2,3)); //3

    五、实参对象callee和length属性

      callee指向当前正在执行的函数,length代表了当前调用函数的实参数量。 

    1 function X(){
    2     console.log(arguments.length);//0
    3     function Y(){
    4         console.log(arguments.caller);//Y
    5     }
    6     Y();
    7 }
    8 X();

    六、函数的属性

      1、caller 

      如果一个函数f是在全局作用域内被调用的,则f.caller为null,相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数.该属性的常用形式arguments.callee.caller替代了被废弃的 arguments.caller.  

    1 function X(){
    2     console.log(X.caller);//null
    3     function Y(){
    4         console.log(Y.caller);//X
    5     }
    6     Y();
    7 }
    8 X();

      2.length属性指明函数的形参个数。 

    1 function X(a,b){
    2   console.log(X.length);//2
    3 }
    4 X();

      3、prototype属性

      每个函数都有prototype属性,该属性指向一个对象,这个对象成为原型对象。当时用该函数创建一个对象,对象会从原型对象继承属性。

      4、call()和apply()

      函数的这两个方法使的函数可以作为其他对象的方法调用。即使对象没有这个方法。

      call()和apply()的一个参数是函数调用的上下文对象,可以是null和undefined,当时null和undefined的时候,会用全局对象代替,当时原始值的时候,会转化为对应的包装对象。

      第二个参数是函数的调用的参数是要传入的参数。apply()把函数要传入的参数以数组的形式传入。

      5、bind()

      bind()用来将一个函数f绑定到一个对象o,并返回一个新的函数,这个新的函数会把f作为o的方法调用。

      bind()可以接受额外的参数,额外的实参会作为函数的参数传入; 

    1 function add(x,y){return x+y};
    2 var x=add.bind(null,1,2);//把函数绑定到null,x绑定1;y绑定2
    3 console.log(x());//3

      当绑定完的返回的新函数length属性为原函数的length减去绑定的实参个数。所以上面的函数x的length为0;

       当绑定的函数作为构造函数时,函数无prototype属性,函数的this会忽略绑定的对象。创建的对象的原型指向原来函数的prototype,使用instanceof验证时,绑定函数和原函数没有区别。 

    1 function X(a,b){
    2     this.a=a;
    3     this.b=b;
    4 }
    5 var o=Object.create({x:1});
    6 var x=X.bind(o,1,2);//把函数绑定到o,a=1;b=2
    7 var z=new x();
    8 console.log(z instanceof x);//true
    9 console.log(z instanceof X);//true

      6、toString()

      大多数函数的toString()返回源码,内置函数的toString()返回[native code].

    七、函数的使用

      JavaScript中的函数是一个值,可以赋值给变量、对象的属性、数组的元素,还可以作为函数的参数。数组的sort()方法的参数就是一个函数,允许他设置数组的元素的排序规则。

      函数是一个对象,我们可以给函数定义属性。

    1 //用函数的属性保存一个值,这样可以减少全局变量的使用
    2 XX.n=0;
    3 function XX(){
    4     return XX.n++;
    5 }

      作为命名空间的函数:函数内部定义的变量只在函数内部有效,而不会污染全局命名空间。模块的定义常用到这个方法,因为模块会在不同的程序中运行,我们不能保证模块中定义的变量是否在程序中已经存在,我们可以把变量定义在一个函数内部,这样变量的作用域就不是全局的。 

    1 (function(){
    2     //moudle中的代码
    3 }())

    八、闭包

      闭包:函数的变量可以隐藏于作用域链之内,因此看起来像函数把变量包裹起来了一样。

      JavaScript采用词法作用域,函数的执行依赖变量的作用域,这个作用域实在函数定义的时决定的,而不是在函数调用时决定的。为了实现这种词法作用域,JavaScript的函数不仅包含代码的逻辑部分,还要引用当前的作用域链。

     1 var scope="global scope";
     2 function f(){
     3     var scope="local scope";
     4     function fun(){
     5         return scope;
     6     }
     7     return fun;
     8 }
     9 var x=f()();
    10 console.log(x);//"local scope"

      函数定义的时候会保存一个作用域链,当函数调用的时候会创建一个保存函数局部变量的对象,把对象添加到作用域链上。当函数返回时会从作用域链删除该对象。当函数内部存在嵌套函数,嵌套函数的作用域链指向该对象,如果嵌套函数在外部函数中保存下来,外部函数返回的时候变量绑定对象会被回收,但是如果嵌套函数被返回或者存储在某处的属性里,则会有一个外部引用指向该函数,他的作用域链上的绑定对象则不会被回收。当我们调用函数时会从函数的作用域上查找变量,所以上面我们访问到的还是局部变量。

      我们可以利用闭包来实现变量的私有。  

     1 function fun(){
     2     var n=10; 
     3     return {
     4         add:function f(){
     5             return  n++;
     6         },
     7         set: function g(){
     8             n=0;
     9         }
    10     }
    11 }
    12 var o=fun();
    13 o.add();//10
    14 o.set
    15 o.add();//0

      当fun()方法调用返回后,只能通过函数的嵌套函数才能访问到局部变量n,这个变量就变成了一个私有变量。两个嵌套函数(闭包)共享变量n.

      很多时候我们不希望私有变量共享。

     1 function fun(){
     2    var arr=[],i=0;
     3    for(i;i<10;i++){
     4        arr[i]=function(){
     5            return i;
     6        }
     7    }
     8    return arr;
     9 }
    10 var a=fun();
    11 a.forEach((ele)=>{
    12     console.log(ele());//结果全是10;
    13 });

      上面的代码中我们创建了10个闭包。10个闭包共享变量i; 

     1 function fun(){
     2    var arr=[],i=0;
     3    for(i;i<10;i++){
     4        arr[i]=(function(x){
     5             function f(){
     6                 return x;
     7             }
     8             return f;
     9        }(i));
    10    }
    11    return arr;
    12 }
    13 var a=fun();
    14 a.forEach((ele)=>{
    15     console.log(ele());//结果全是0....9;
    16 });

      这个例子中我们把i作为参数传给不同的函数的形参x,然后让闭包中的x不共享。

      当使用闭包是无法访问到外部函数的this和arguments。只能将其赋值给一个变量才能访问到。

    九、Function构造函数

    1 var z=new Function('x','y',"return x+y");

      上面的函数等价于var z=function(x,y){return x+y}; 

  • 相关阅读:
    Asp.net 基础4(自定义控件的使用之客户端脚本生成)
    Asp.net 基础3(自定义控件的使用)
    wpf 可以取消的单选checkbox
    wpf MaskedTextBox
    自定义 日期格式的datePicker
    wpf datagrid no record found style
    Sql语句绝妙用法
    .net反射简介
    c# 正则表达式小结
    如何获取地址栏地址
  • 原文地址:https://www.cnblogs.com/yiluhuakai/p/8564239.html
Copyright © 2020-2023  润新知