Javascript基础——Javascript语言核心(5):函数


函数

8.1 函数的定义

函数使用function关键字来定义,可以用函数定义表达式或者函数声明语句

function fn(){}
var fn=function(){}

函数声明语句会被提前,可以被在它定义之前出现的代码调用;而使用表达式方式定义的函数,变量声明提前了,但是变量赋值不会提前。所以,以表达式方式定义的函数在定义之前无法调用

8.2 函数调用

有四种方式:

  • 作为函数
  • 作为方法
  • 作为构造函数
  • 通过它们的call()和apply()方法间接调用

8.2.2 方法调用

方法是保存在一个对象属性里的函数。

var o={};

//给o定义一个名为m()的方法
o.m=function fn(){};

//方法调用
o.m();

函数嵌套时,如果想访问外部函数的this,需要保存到变量里。

var self = this;

8.2.3 构造函数调用

如果函数或者方法调用之前带有关键字new,就构成构造函数调用。

var o = new Object();

8.3 函数的实参和形参

8.3.1 可选形参

当调用函数时传入的实参比形参个数少,剩下的形参都将设置为undefined值。

函数调用时,不能忽略第一个实参,传入第二个实参。必须显示传入null或者undefined。

在函数定义中使用注释/*optional*/来强调形参是可选的。

扫描二维码关注公众号,回复: 2707150 查看本文章
function fn(o,/*optional*/a){
    a = a || [];    //如果函数调用时省略了第二个实参,那么创建一个空数组
}
fn({});

8.3.2 可变长的实参列表:实参对象

在函数体内,标识符arguments是指向实参对象的引用。实参对象是一个类数组对象(概念参见7.11)。

fn(x)的实参是x,也可以通过arguments[0]获得。arguments包含length属性。

下面这个函数可以接受任意数量的实参,这种函数称为“不定实参函数”

//返回实参中的最大值
function max(/*...*/){
    var max= Number.NEGATIVE_INFINITY;
    for(var i=0;i<arguments.length;i++){
        if(arguments[i] > max){
            max=arguments[i];
        }
    }
    return max;
}
max(1,5,10,99,81); //99

8.3.3 将对象属性用做实参

当一个函数包含超过三个形参,要记住调用顺序很困难。最好通过名/值对的形式来传入参数,这样参数的顺序就无关紧要。

function arraycopy(from,from_start,to,to_start,length){
    //逻辑代码
}
function easycopy(args){
    arraycopy(args.from,
                args.from_start||0, //设置默认值
                args.to,
                args.to_start || 0,
                args.length)
}

//调用
var a=[1,2,3], b=[];
easycopy({from:a,to:b,length:3});

8.4 作为值的函数

Javascript中,函数不仅是一种语法,也是,可以将函数赋值给变量

var a=[function(x){return x*x},20];
a[0](a[1]); //=> 400: 虽然看上去很奇怪,但这是合法的函数调用表达式

8.4.1 自定义函数属性

Javascript中,函数并不是原始值,而是一种特殊的对象,所以,函数可以拥有属性

当函数需要一个“静态”变量,在调用时保持值不变,最方便的方式是给函数定义属性,而不是全局变量(污染命名空间)。

下面这个例子,实现每次调用函数都会返回唯一的整数:

//初始化函数对象的计数器属性
//因函数声明提前,因此可在之前给成员赋值
uniqueInteger.counter=0

function uniqueInteger(){
    return uniqueInteger.counter++;
}

//调用结果
uniqueInteger() //=> 0
uniqueInteger() //=> 1
uniqueInteger() //=> 2

8.5 作为命名空间的函数

因为函数的作用域,可以定义一个函数作为命名空间,其内定义的变量都不会污染到全局命名空间。

定义一个匿名函数,会立即调用:

(function(){
    //模块代码
}());

注意:function前的括号是必需的,不写会被解析为声明语句。

8.6 闭包

闭包概念: 函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性成为“闭包”。

var scope='global scope';
function checkscope(){
    var scope='local scope';
    function f(){
        return scope;
    }
    return f;
}
checkscope()(); //=> "local scope"

垃圾回收

如果函数定义了嵌套函数,并将它作为返回值返回或者存储在某处的属性*v,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当做垃圾回收*,并且它所指向的变量绑定对象也不会被当做垃圾回收。

闭包容易造成“循环引用”,在某些浏览器下会造成内存泄露

闭包示例

在8.4.1中的uniqueInteger()函数,可能被恶意重置。如果使用闭包,可以将局部变量用作私有状态。

var uniqueInteger=(function(){
    var counter=0;
    return function(){return counter++;}
}());

uniqueInteger(); //=> 0
uniqueInteger(); //=> 1

当外部函数返回之后,其他任何代码无法访问counter变量,只有内部函数才能访问它。

8.7 函数属性、方法和构造函数

函数是Javascript中特殊的对象,所以可以拥有属性方法,也可以用Function()构造函数来创建新的函数对象。

8.7.1 length属性

  • 函数体里,arguments.length表示传入函数的实参个数
  • 函数的length属性是只读的,表示形参个数(或期望传入的实参个数)
function fn(x,y){
    return arguments.length;
}

fn.length   //=> 2: fn函数有2个形参
fn(1,2,3,4) //=> 4: 实参个数为4个

8.7.2 prototype属性

每个函数包含prototype属性,指向“原型对象”的引用。当将函数用作构造函数时,新创建的对象会从原型对象上继承属性。

8.7.4 bind()方法

bind()将函数绑定至某个对象。当在函数f()上调用bind()方法病传入一个对象o作为参数,这个方法将返回一个新的函数。

function f(y){ 
    return this.x +y;
}

var o = {x:1};
var g = f.bind(o);

g(2) //=> 3

8.7.6 Function()构造函数

函数可以通过Function()构造函数来定义。

var f = new Function("x","y","return x*y;");

//等价于:

var f = function(x,y){ return x*y; }

注意:这种方式创建的函数并不是使用词法作用域,相反,函数体代码的编译总会在顶层函数执行。Function()狗仔函数在实际编程中很少用到。

var scope='global';
function constructFunction(){
    var scope='local';
    return new Function("return scope"); //无法捕获局部作用域
}

//所返回的函数使用的不是局部作用域
constructFunction()(); //=> "global": 通过Function()构造函数

8.8 函数式编程

8.8.2 高阶函数

高阶函数(higher-order function)就是操作函数的函数。接收一个或多个函数作为参数,并返回一个新函数。

下例中not()函数就是一个高阶函数:

function not(f){
    return function(){
        var result = f.apply(this,arguments);
        return !result;
    }
}

var even = function(x){
    return x % 2 === 0; 
}

var odd=not(even);
[1,1,3,5,5].every(odd); //=> true: 每个元素都是奇数

猜你喜欢

转载自blog.csdn.net/joyce_lcy/article/details/80743924