在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;