练习使用的浏览器IE11
JS 中Function类型实际上是一种对象,每一个函数实际上都是Function类型的一个实例,每一个函数都有一些默认的属性和方法。由于函数是对象,故函数名实际上也是一个指向函数对象的指针变量
1、声明一个函数
直接用关键字function来声明函数,JS是弱类型的语言,声明的时候参数个数不限,只是需要写参数名,不需要写参数的关键字var,不需要指定返回值以及类型,如果有返回值直接在函数后面一个return value 即可。
方法一:function func(num1,num2){return 1;}//num1,num2是参数名,返回值为1
方法二:利用变量来声明函数,var box=function(num1,num2){};相当于给window对象的自定义属性box注册方法
方法三:利用析构函数来声明,但是最好不要用这种方式来声明,因为这种方式浏览器会解析两次,效率不高,第一次是解析整个ECMAScript表达式,第二次是解析析构函数中传递的字符串列表,var box=new Function('num1','num2','return num1+num2');注意析构函数里面的参数以及语句是带有引号的。这种方式能够更好的理解 Function是一个对象的,函数名是一个指针的概念
2、调用函数
方法一中声明的函数直接写函数名就可以调用[fun(10,20)],
方法二和方法三声明的函数调用时用变量名后面加括号里面写上要传递的参数值[box(10,20)];
函数的返回值可以直接赋值给一个变量[var box=func(20,10);],也可以当做实参直接传递给另外的函数[alert(func(10,20));]
ECMAScript 中的函数名本身就是变量,所以函数也可以作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数, 而且可以将一个函数作为另一个函数的结果返回
//将一个函数作为结果返回 其实就相当于执行这个函数,然后把这个函数的返回值给返回 function sum(num1,num2){ return num1+num2; } function func(num1){ return sum(num1,10); } alert(func(10));//20//其实函数名,也就是一个对象的变量,执行的是函数的地址,相当于一个指针//将函数名当做一个参数传递给另外一个函数, function sumFunc(num1,num2){ return num1+num2; } function func(sum,num1){ return sum(num1,10); } alert(func(sumFunc,10));//20
JS 中没有函数重载的说法,函数调用的时候,会以就近原则来调用
JS 中调用函数的时候允许调用者和被调用这的参数个数不一样,也不会报错,但是如果参数个数不够的话,在执行时因为有的参数没有赋值可能会报错,参数时从前向后对应传递接收的
3、函数的内部属性 arguments
arguments 是一个类数组,用来保存函数传递过来的参数,数组类型
在声明函数的时候,有的时候我们并不知道调用者到底要传递多少个参数过来,比如说,求一串数的累加和,如果调用者不是用数组传递过来而是用直接传递给函数的方式传递[func(10,20...)],那么在声明函数实体的时候就不知道要声明多少个参数,这时可以不写参数名,在函数内部用arguments来代替,arguments是一个类数组,保存的是拥有这个对象的函数的参数的值,用索引的方法既可以获取对应的参数的值,使用如下:
function func(){ var res=0; for(var i=0;i
arguments 中还有一个很重要的属性就是callee,是一个指针变量,指向的是拥有这个arguments类数组的函数,其实也就是arguments所在的函数本身,在递归的时候最好用这个属性,因为如果函数名改变了,也不需要改变内部的实现,arguments.callee()始终代表的是这个函数本身
//用arguments.callee的好处是,当函数名改变了以后,不需要改动递归出的函数, function box(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); //arguments.callee代表的是函数的本身,故和上面是同样的效果 } } alert(box(3));//6
4、函数的内部属性 this
this 这个属性代表的是它所在的对象本身,和C#中this代表实体对象本身是一样的,this 引用的是函数以执行操作的对象,或者说函数调用语句所处的那个作用域
window是JS中最大的一个对象,在window对象中声明一个变量其实就是给window这个对象声明一个属性,var box=1;相当于 window.box=1;也就等价于this.box=1;
当在全局作用域中调用函数时,this 对象引用的就是 window。
在显示的声明一个对象box,这个box中使用的this就代表的是box本身,this.color就是返回的box中属性color的值,而不是window对象中color的值
// this 代表的是坐在的对象本身,下面在对象box中的this,就代表对象box var color='红色'; // window对象的属性, var box={ color:'蓝色', run:function(){ alert(this.color);//蓝色 return this.color; } } alert(window.color);//红色 alert(this.color); //红色 此处this代表的是window对象,故this.color是代表的window的属性 alert(box.run()); //蓝色 window.co='hh'; //和上面的color是等价的,都属于window对象的属性 alert(this.co);
5、函数的属性 length
函数的属性length代表的是函数希望接收的参数的个数,是由声明函数时参数列表中的个数决定的
6、函数的属性 prototype
prototype 是保存所有实例方法的真正所在,也就是原型。
prototype 下面有两个方法 apply(),call(),这两个方法都是函数非继承而来的方法, 是每一个函数都具有的方法。这两个方法的用途都是在特定的作用域中调用函数,也就是说调用特定的对象下面调用函数,(当然这个对象不一定已经声明有这个方法),实际上也就是等价于设置函数内部this对象的值,有点类似于C#的反射中调用对象的方法。
func.apply():这个方法有两个参数,第一个是要执行这个方法的作用域,也就是传递一个对象过去,第二个参数是一个数组,这个数组中是存放的调用的函数func的实参,也就是要传递给func的值,当然第二个参数可以省略。func.apply(this, [num1, num2]);。如果是在一个函数中调用可以用arguments把这个函数的参数传递过去,前提是这个类数组中有参数。但是最好是保证这个类数组中存放的是你想要传递给func函数的实参的值。虽然个数不匹配也不会出错,但是业务上可能不对
func.call():这个方法和上面的apply()方法是一样的,不同的是参数,第一个同样是作用域,是一样的,其余的参数是直接传递给函数的,而不是传递一个数组过去。就是说传递的参数顺序和方式是按照正常调用函数的形式和方法。func.call(this, num1, num2);
这两个方法最主要的功能是是能够扩展函数赖以运行的作用域,也就是改变函数运行所在的作用域
使用这apply()和call()这两个方法来扩充作用域最大的好处是对象不需要与方法发生任何的耦合关系,也就是上面说的对象中可能不存在这个方法,但只要存在这个对象就OK。【耦合:关联的意思,修改和维护会发生连锁反应】。也就是说 box 对象和sayColor()方法之间不会有多余的关联操作,比如 box.sayColor = sayColor;[ box对象中无需显示写上这条语句,也可以通过sayColor.call(box,'red')或者apply来调用方法sayColor,并且调用时sayColor方法的作用域是在对象box内部 ].
//call()和apply()方法最主要的是用于扩展函数依赖的作用域var color='red';var box={ color:'green'}function sayColor(){ return this.color;}alert(sayColor()); //red 对象是windowalert(sayColor.call(this)); //red 对象是windowalert(sayColor.apply(this)); //red 对象是windowalert(sayColor.call(window)); //red 对象是windowalert(sayColor.apply(window)); //red 对象是windowalert(sayColor.call(box)); //green 对象是boxalert(sayColor.apply(box)); //green 对象是box
练习的代码:以IE10为主
1 /* 函数的声明 2 3 //声明一个函数,没有参数和返回值 4 function func(){ 5 alert('diao yong di shi hou zhi xin'); 6 } 7 func(); 8 9 //声明一个函数,带有两个参数,由于JS是弱类型的语言,故函数的参数时不需要使用var的 10 function func(num1,num2){ 11 alert(num1+num2); 12 } 13 func(10,20); 14 15 //声明一个函数,带有两个参数和返回值,JS中返回值直接用return即可,函数名前不需要标注带有返回值 16 function func(num1,num2){ 17 return num1+num2; 18 } 19 alert(func(10,20));//30 20 21 //可以把函数的返回值直接赋值给一个变量,然后直接操作变量 22 function func(num1,num2){ 23 return num1+num2; 24 } 25 var a=func(10,20); 26 alert(a); //11 27 28 //return还有一个功能就是,结束函数的执行 29 function func(num1,num2){ 30 if(num1>10){ 31 return 11; 32 } 33 return num1+num2; 34 } 35 alert(func(13,20)); //11 36 37 // JS 调用的时候传递的参数个数和函数原型中参数个数可以不一样 38 function func(num1,num2){ 39 return num1+num2; 40 } 41 42 alert(func(20,'ahc',9)); 43 44 //ECMAScript 函数不介意传递进来多少参数,也不会因为参数不统一而错误。实际上, 45 函数体内可以通过 arguments 对象来接收传递进来的参数,arguments 可以用数组来取值 46 function func(){ 47 var res=0; 48 for(var i=0;i