所谓过程式编程(或函数式编程),最重要的语法就是函数,js虽然号称OOP语言,但实际上函式编程是更为常用且大家熟悉的编程方式。这里就几个重要概念进行说明。
总结来说,函数是js语言的第一类对象,可以被调用、赋值、传递....
函数定义
function 函数名(参数1,参数2,参数3...){
函数体语句
renturn 返回值;
}
说明:
1、函数体return关键字指定返回值,因为是弱对象语言,因此不需要在定义中指定函数返回值,也可以没有return语句,返回值是undefined;
2、参数不用指定类型,如果类型很重要,需要使用typeof方法进行检测。参数个数可变,且调用时个数可以不和参数个数匹配。
在函数内定义函数,叫嵌套函数。
用函数直接量定义函数,函数直接量是表达式,可以定义匿名函数。
function f(x){ return x*x;} var f = function(x){ return x*x;}; //第一行是常规定义方式,第二行匿名函数量的方式定义函数。
虽然直接量匿名定义函数,也可以对函数命名,这在递归编程中非常有用。
var f = function fact(x){ if (x<-1) return 1; else return x*fact(x-1); };
函数参数
函数可以以任意数目的参数来调用,而不管函数定义中参数多少,向任何函数传递任意类型的参数都是合法的。
1、可选参数
当调用函数时,参数少于申明的参数个数的时候,其他参数的值是undefined。因此希望编写某些参数可选的安全的函数,方法是为能够忽略的参数分配一个合理的默认值。但参数的顺序是必须的,因此可选参数应放在最后。
function copyPropertyNamesToArray(o,/* optional */ a){ if(!a) a=[]; //如果undefined 或者 null,使用空数组 for(var property in o ) a.push(property); return a; } var a = copyPropertyNamesToArray(o); //不使用可选的参数a copyPropertyNamesToArray(p,a); //使用两个参数
2、Arguments对象
在函数体内,可以用arguments标示符引用auguments对象,arguments对象是一个类似数组的对象,可按照数目获取传递给函数的参数值,并定义了callee属性。
arguments.length属性返回参数个数,arguments[0]返回第一个参数的值,使用数组下标方式获取参数值。
属性callee用来引用当前正在执行的函数,可用来对未命名的函数递归调用自身。
function(x){ if(x<=1) return 1; return x*arguments.callee(x-1); }
如何不用记住参数顺序调用参数?
前面讲到,调用函数参数个数虽然不限,但参数顺序是必须保证的,这比较麻烦。让参数以键名/值对的方式传递参数,是一个好办法。实现方法是定义一个对象,用对象属性名/值作为函数参数。
function arrayCopy(/*array*/ from,/*index*/from_start,/*array*/ to,/*index*/to_start,/*integer*/ length) { // 方法代码,数组from从from_start位置开始复制长度为length的数据到到数组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,4]; var b=new Array(4); easyCopy({from:a,to:b,length:4});
函数可以作为数据赋值给变量。
function square(x) { return x*x;} var a=square(4); //a=16 var b=square; //b引用到square var c=b(5); //c=25
函数可以复制给对象的属性,称为方法。方法其实不过是存储在对象属性中的并且通过对象来调用的函数,不过和通常函数不同的是,对象会默认给方法赋值一个对象实例,标示符是this。
var o=new Object; o.square=function(x){ return x*x;} y=o.square(16);
还可以复制给数组元素。
var a=new Array(3); a[0]=function(x){ return x*x; } a[1]=20; a[2]=a[0](a[1]); //a[2]=400
函数还可以作为参数传递给其他函数。
函数的属性和方法
函数是js对象的一种特殊类型,也具有属性和方法。
length属性:只读属性,返回参数个数;
prototype属性:预定义的原型对象;
函数自定义属性:可以在函数内部定义变量作为函数的属性;
apply()和call()方法:该方法可以像调用其他对象的方法一样调用函数。第一个参数是要调用的函数的值,在函数体内这个参数是关键字this,剩余参数是要传递给要调用的函数的值。
f.call(o,1,2); 等同于: o.m=f; o.m(1,2); delete o.m;
函数作用域和闭包
调用对象
当js解释器调用一个函数,它首先将作用域设置为定义函数的时候起作用的那个作用域链。接下来,在作用域链前面添加一个新的对象,叫做调用对象。调用对象用arguments属性调用函数的Arguments对象,函数的命名的参数和var语句的局部变量添加到调用对象的后面。
闭包
子函数可以使用父函数中的局部变量,这种行为就叫做闭包!按照js作用域链原理,嵌入函数总是能够访问外部函数的所有参数和变量。因此,所有函数都是闭包的,嵌入函数可作为闭包使用。