ECMAScript中Function类型

在ECMAScript中,Function(函数)类型其实是对象。每一个函数都是Function类型的实例,并且都与其余引用类型同样具备属性和方法。因为函数是对象,所以函数名实际上也是一个指向函数对象的指针。
一.函数的声明方式
1.普通的函数声明算法

function box(num1,num2) {        //普通函数的声明方式
    return num1+num2;
}

alert(box(1,2));                //返回3

2.使用变量初始化函数数组

var box=function(num1,num2) {    //使用变量初始化函数
    return num1+num2;
};

alert(box(1,2));                //返回3

3.使用Function构造函数app

var box=new Function('num1','num2','return num1+num2');         //使用new的构造函数来声明函数
alert(box(1,2));                                                //返回3
alert(typeof box);                                              //字符串仍是function

注意:第三种方式咱们不推荐,由于这种语法会致使解析两次代码(第一次解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。但咱们能够经过这种语法来理解"函数是对象,函数名是指针"的概念。函数

二.做为值的函数
1.不是做为函数来传递的,而是做为函数的返回值来传递的性能

function box(sum,num){
    return sum+num;           //把num做为跟sum相加的数字
}

function sum(num){
    return num+10;
}

var result=box(sum(10),10);   //20,10sum(10)这里传递的是函数的返回值,和普通的变量同样,没区别
alert(result);                //结果是:30

要把函数自己做为参数传递,而不是函数的结果this

function box(sum,num) {
    return sum(num);          //把num做为参数传到sum()
}

function sum(num){
    return num+10;
}

var result=box(sum,10);       //这里sum是一个函数,看成参数传递到另一个函数里,而不是函数的返回值
alert(result);                //20

三.函数内部属性
在函数内部,有两个特殊的对象:arguments和this。arguments是一个类数组对象,包含着传入函数中的全部参数,主要用途是保存函数参数。但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。spa

function sum(num) {
    if (num<=1){                    //传入的num若是小于等于1
        return 1;                   //返回1           
    } else {
        return num * sum(num-1);    //若是传入的是4至关于4*3*2*1=24阶乘,递归
    }
}

alert(sum(4));                      //返回24

对于阶乘函数通常要用到递归算法,因此函数内部必定会调用自身;若是函数名不改变是没有问题的,但一旦改变函数名,内部的自身调用须要逐一修改。为了解决这个问题,咱们可使用arguments.callee 来代替。prototype

function box(num) {
    if (num<=1) {                             //传入的num若是小于等于1
        return 1;                             //返回1  
    } else {
        return num*arguments.callee(num-1);     //使用arguments.callee,调用自身,实现递归
    }
}

alert(box(4));                                //返回24

函数内部另外一个特殊对象是this,其行为与Java和C#中的this大体类似。换句话说,this引用的是函数据以执行操做的对象,或者说函数调用语句所处的那个做用域。当在全局做用域中调用函数时,this对象引用的就是window。
window是一个对象,并且是JS里面最大的对象,是最外围的对象指针

//打印一下window
alert(typeof window);   //window是对象,类型是object对象,window表示全局
//打印this
alert(this);            //[object Window]this目前表示的是window,由于在window的范围下
alert(typeof this);        //this和window如出一辙,因此this就是window
var color='红色的';            //这里color就是全局变量,而这个变量又是window的属性
//alert(window.color);        //输出:红色的。说明color是window下的属性
alert(this.color);            //输出:红色的。同上

因此window.color='红色的'至关于var color='红色的';是同样的code

例1:

window.color = '红色的';

var box={
    color:'蓝色的',                //这里的color是box下的属性,也就是局部变量
    sayColor:function(){
        alert(this.color);        //在打印出:蓝色的。这里this,咱们肯定了是表明的box对象。
    }
};

alert(this.color);               //先打印出:红色的
box.sayColor(); 

例2:

window.color='红色的';

function sayColor() {
    alert(this.color);      //先打印出:红色的后打印出蓝色的、这里执行的时候是动态的,第一次在window下,第二次在box下
}

sayColor();                 //这里调用sayColor,其实范围仍是在window下

var box = {
    color : '蓝色的'
};

box.sayColor = sayColor;    //这段代码至关sayColor:function()
box.sayColor();             //这里执行的是box里面的this.color,至关于alert(this.color)

四.函数属性和方法
ECMAScript中的函数是对象,所以函数也有属性和方法。每一个函数都包含两个属性:length和prototype。其中,length属性表示函数但愿接收的命名参数的个数。

function box(name,age){
    return name+age;
}

alert(box.length);           //查看传了几个属性:2

对于prototype属性,它是保存全部实例方法的真正所在,也就是原型。这个属性,咱们将在面向对象一章详细介绍。而prototype下有两个方法:apply()和call(),每一个函数都包含这两个非继承而来的方法。这两个方法的用途都在特定的做用域中调用函数,实际上等于设置函数体内this对象的值。
原函数相加方法:

function box(num1,num2){
    return num1+num2;                 
}

alert(sayBox(10,10));                 //20

经过apply冒充另一个函数:

function box(num1,num2){
    return num1+num2;                    //原函数
}

function sum(num1,num2) {                //apply和能够冒充另一个函数(sum能够冒充box能够执行box的功能)
    return box.apply(this,[num1,num2]);  //this表示window做用域,[]表示传递的参数
}

alert(sum(10,10));                        //20

经过apply当数组传递:

function box(num1,num2) {                 //原函数
    return num1+num2;
}

function sum2(num1,num2) {
    return box.apply(this,arguments);       //这个能够当数组传递,arguments
}

alert(sum2(10,10));

call()方法于 apply()方法相同,他们的区别仅仅在于接收参数的方式不一样。对于call()方法而言,第一个参数是做用域,没有变化,变化只是其他的参数都是直接传递给函数的。

function box(num1,num2) {               //原函数
    return num1+num2;
}

function sum(num1,num2) {
    return box.call(this,num1,num2);    //call只是传递参数不一样,其余和apply同样
}

alert(sum(10,10));                      //20

事实上,传递参数并非apply()和call()方法真正的用武之地;它们常用的地方是可以扩展函数赖以运行的做用域。

var color='红色的';              //全局

var box={                       //box对象
    color:'蓝色的'               //局部
};

function sayColor(){            
    alert(this.color);                
}

sayColor();                       //全局打印:红色的
//用call是实现对象冒充,冒充box下,冒充window下
sayColor.call(window);            //冒充window:红色的
sayColor.call(this);              //this就是window:红色的
sayColor.call(box);               //冒充box,做用域就在box对象里面,因此color就是alert(this.color);打印:蓝色的

这个例子是以前做用域理解的例子修改而成,咱们能够发现当咱们使用call(box)方法的时候,sayColor()方法的运行环境已经变成了box对象里了。使用call()或者apply()来扩充做用域的最大好处,就是对象不须要与方法发生任何耦合关系(耦合,就是互相关联的意思,扩展和维护会发生连锁反应)。也就是说,box对象和sayColor()方法之间不会有多余的关联操做,好比box.sayColor=sayColor;

相关文章
相关标签/搜索