JavaScript 函数 和 MooTools Native Extensions之Functions篇
JavaScript 函数
引言
函数是几乎所有你用 JavaScript 编写的有用的功能的核心。一般而言,函数可以将一个程序分为若干逻辑块,每个块实现某个特定的功能。函数是 JavaScript 程序设计语言最主要的特征,而 JavaScript 之所以具有这么大的吸引力原因之一就是它特有的使用和创建函数的方式。如果你之前曾经用 PHP 或 Java 之类的语言编写过某些程序,那么你就会对 JavaScript 中的函数感觉得心应手;如果你没有这样的经验,也不用担心。
本文会阐述为什么要使用函数,然后我们将介绍函数的语法,并说明如何创建和使用函数;我们在介绍JavaScript函数的同时,也不会忘记MooTools中是如何使用的,同时我们还会学到MooTools对JavaScript 的Function prototype扩展的所有方法。
为什么要使用函数
“为什么?”要使用函数的的问题就有了一个非常简单的答案:函数是基本的组成模块,通过函数你就可以结构化自己的代码的,从而提高对其作用的理解,并可以重复使用你所编写的函数,以避免在多处地方重复编写同样的代码片段。如果你将自己的程序分为若干小片段,每个小片段完成一项确定的任务的话,该程序就更容易编写了。
此外,在深思熟虑之后,将你的代码分解为若干函数,会使得将来对代码的维护容易得多。一般来说,你写的大约95%的代码会包含在函数中。这使得函数成为重要的JavaScript结构之一。
基本函数语法
在JavaScript中可以使用关键字function来定义函数。
1 2 3 4 5 6 7 8 9 10 11 12 | // function myFun_1(){ alert("这是一个简单的函数!"); } // function myFun_2(nationality,name){ alert("我是来自 "+ nationality+ " 的 " + name); } |
- 跟子function关键字后面的myFun是函数名。
- 在函数名后面必须有圆括号,它可能包含0个参数或多个参数,其中的每个参数用逗号隔开。
- 组成函数体的语句被包含在一个由{}来定界的函数块中。
替代语法
1 2 3 4 5 | var myFun=function(nationality,name){ //函数主体 } |
注意:此方式创建匿名函数时比较有用
当你调用函数时,只需函数名后面紧跟着圆括号和圆括号里包含的参数就行了。
1 2 | myFun_1(); myFun_2("中国","rainbow"); |
函数定义时可以设置参数,如果传给函数的参数个数不够,则从最左边起依次对应,其余的用undefined赋值,如果传给函数
的参数多于函数定义参数的个数,则多出的参数被忽略.
1 2 3 4 5 6 | function myprint(s1,s2,s3) { alert(s1+"_"+s2+"_"+s3); } myprint(); //undefined_undefined_undefined myprint("string1","string2"); //string1_string2_undefined myprint("string1","string2","string3","string4"); //string1_string2_string3 |
参数:向函数传递数据
向函数传递信息以影响其行为,在很多情况下这都能使函数更灵活,更有用。
在前面我们曾提到过,函数定义紧接在函数名之后的是一对圆括号。这就是该函数的参数列表。为了接受来自调用程序的输入信息,你只需指定一个用逗号分隔的参数列表,这些参数就是你的程序要接收的信息的对应变量。你可以指定任意多数量的变量,并且参数列表中所提到的所有变量名都可以在函数体之内被引用,就跟任何其它变量一样。
我们知道Javascript函数可以以任意数目的参数来调用,而不管函数定义中的参数名字有多少个。由于函数是宽松类型的,它就没有办法声明所期望的参数类型,并且,向任何函数转递任意类型的参数是合法的。
一个参数
1 2 3 4 5 6 7 | function myFun(parameter){ alert("我获得了参数内容是: "+parameter); } window.addEvent('domready', function(){ myFun("我是一个参数"); }); |
多个参数
1 2 3 4 5 6 7 8 | function f(x,y,z){ var sum=x+y+z; alert("求三个数之和:"+sum); } window.addEvent('domready', function(){ f(2,4,8); }); |
可选参数
如果你调用了该函数,却忘记传给它一个参数值,那么该参数就会取 undefined 值。
编写这样的函数常常是很有用的:某些参数为可选的并且在调用函数的时候可以忽略它们。
要做到这一点,必须能够为忽略掉的参数分配一个合理的默认值(或者指定为null).
你可以在自己的函数体内添加参数检验代码以防止无心之错
1 2 3 4 5 6 | if ( parameter == undefined) { // 如果调用程序没有提供`parameter`变量, // 这个表达式的值就为‘true’ // 你就可以在这个if语句中编写一些代码 // 来阻止程序出错。 } |
当我们不想求三个数之和,而想求两个数之和时,不用再重新编写求和函数了,只需改造原有的求和函数就行了。
1 2 3 4 5 6 7 8 9 | function f(x,y,z){ var z=z||null;//为忽略掉的参数分配一个合理的默认值 var sum=x+y+z; alert("求和:"+sum); } window.addEvent('domready', function(){ f(2,4); }); |
注意:
在使用可选的参数来设计函数的时候,应该确保把可选的参数放在列表的末尾,以便它们可以被忽略。
正如上面的例子所示。
传递给函数的隐含参数:arguments
当进行函数调用时,除了通过为参数赋值的方式来向函数传递值之外,函数还可以通过自动生成的arguments数组来获得相应的值。
即使函数在声明时没有定义任何参数,在调用该函数时也将传递一个或多个参数。
这些位于arguments数组里面的参数乃然可用。这对于编写可用接收任意多个参数的函数将十分有用。
arguments是一个类似数组但不是数组的对象,说它类似是因为它具有数组一样的访问性质,可以用arguments[index]这样的语法取值,拥有数组长度属性length。arguments对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,例如:
1 2 3 4 5 6 7 8 9 10 11 | function func(a,b){ alert(a); alert(b); for(var i=0;i < arguments.length;i++){ alert(arguments[i]); } } window.addEvent('domready', function(){ func(1,2,3); }); |
代码运行时会依次显示:1,2,1,2,3。因此,在定义函数的时候,即使不指定参数列表,仍然可以通过arguments引用到所获得的参数,这给编程带来了很大的灵活性。arguments对象的另一个属性是callee,它表示对函数对象本身的引用,这有利于实现无名函数的递归或者保证函数的封装性,例如使用递归来计算1到n的自然数之和:
1 2 3 4 5 6 7 8 | var sum=function(n){ if(1==n)return 1; else return n+sum(n-1); } window.addEvent('domready', function(){ alert(sum(100)); }); |
其中函数内部包含了对sum自身的调用,然而对于JavaScript来说,函数名仅仅是一个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,所以使用arguments.callee属性会是一个较好的办法:
1 2 3 4 5 6 7 | var sum=function(n){ if(1<=n)return 1; else return n+arguments.callee(n-1); } window.addEvent('domready', function(){ alert(sum(100)); }); |
callee属性并不是arguments不同于数组对象的惟一特征,下面的代码说明了arguments不是由Array类型创建:
1 2 3 4 5 6 7 8 9 | Array.prototype.p1=1; alert(new Array().p1); function func(){ alert(arguments.p1); } window.addEvent('domready', function(){ func(); }); |
运行代码可以发现,第一个alert语句显示为1,即表示数组对象拥有属性p1,而func调用则显示为“undefined”,即p1不是arguments的属性,由此可见,arguments并不是一个数组对象。记住arguments并非真正的数组,它是一个Arguments对象
函数作为参数
1 2 3 4 5 6 7 8 9 10 11 12 13 | function doSomething(callbackd){ alert("hellow"); if(callbackd){ callbackd(); } } function my_callback(){ alert("world"); } window.addEvent('domready', function(){ doSomething(my_callback); }); |
domready中不使用匿名函数的一种替代方式.
如果你看看MooTools的domready里面我们包装的东西,你会注意到我们把一个函数作为参数传递进去了:
1 2 3 4 | // 建立一个要在domready时调用的函数 var domready_function=function(){ alert("hello function!");} ; // 把函数指定到domready事件 window.addEvent('domready', domready_function); |
return:返回值
return 语句用来规定从函数返回的值。
因此,需要返回某个值的函数必须使用这个 return 语句。
下面的函数会返回两个数相加的值(a 和 b):
1 2 3 4 5 | function sum(a,b) { x=a+b return x } |
当您调用上面这个函数时,必须传入两个参数:
var r_sum=sum(2,3)
而从 prod() 函数的返回值是 5,这个值会存储在名为 r_sum 的变量中。
注意:
请注意一下在调用 return 关键字时,该关键字实际上是结束了你的函数的执行,并将执行权利返回到调用函数的地方。return 语句通常是函数中的最后一个行为;因为函数返回之后就不能再执行任何操作了。
让我们看看下面的代码
1 2 3 4 | function prematureReturner(){ return "Too quick"; alert("Was it good for you?"); } |
在这个函数中,alert函数将不会被调用,因为return语句将终止函数的运行。
return语句的这种终止函数运行的能力在和条件语句组合使用时将变得十分有用。
这样就可以实现仅当条件满足时,函数中的其余部分才会被执行。
例如在我们的对象检测中经常会用到。
1 2 3 4 5 | function initStyleChange(){ if(!document.styleSheets) return; //使用document.styleSheets初始页面 //接下来我就可以使用此对象了 } |
JavaScript 函数小结:
”现在你差不多已经学到了所需要知道的一切,这样你就可以在自己的程序中开始大肆使用函数了。
这些知识是编写高质量 JavaScript 代码的基础知识,如果你经常将自己的代码打包进命名合理的函数,以利于重复使用的话,你的程序就会变得更有条理,更清晰,更易读,也更易于理解了。“
关于JavaScript 函数更多的扩展知识>>
MooTools 对Function的扩展
Function Methods Generate Copies
Function.attempt
尝试执行闭包函数
作用:
create的功能简化版,并且创建闭包函数后执行。实现的即是create中选项’attempt’为true时的功能。
用法:
var result = myFunction.attempt([args[, bind]]);
返回值:
(mixed) 执行后的返回结果;如果执行出错,返回null
Example:
1 2 3 4 5 6 | var say = function(msg){ alert(msg.toString()); return true; }; say(null); //这将抛出一个错误的,null.toString未定义 |
如果使用attempt函数,执行不会通过,但是不会引发错误。
This is a change from MooTools 1.0 where Function.attempt() returned the error thrown instead.
1 2 3 4 5 6 7 | var say = function(msg){ alert(msg.toString()); return true; }; var spoke = say.attempt(null); //仍然会失败,但不会引发错误 //spoke == null |
此函数与以上的应用有同样的作用:
1 2 3 4 5 6 7 8 9 10 | var say = function(msg){ try { alert(msg.toString()); /*in this test, value won't be defined, so it'll throw an error*/ return true; } catch(err) { return false; } } |
Function.create
mootools主要提供了一个create方法来创建闭包,这个方法其实实现了mootools对Function的所有扩展功能,但是一般我们不会直接去用它,而是使用mootools基于这个create方法派生出的其他方法。
作用:
用于创建闭包函数的基础方法.(下面的其他Function扩展方法都基于本方法)
用法:
var createdFunction = myFunction.create([options]);
参数选项列表:
bind : 创建的闭包函数中this所指向的对象。默认指向当前函数。
event: 默认为false;如果为true,则创建的闭包函数将会作为一个事件监
听器,传入的第一个参数是一个event对象;如果为一个类名,则
会创建这个类的一个实例,并把event对象传入该类
arguments:一个以数组形式传入创建的闭包函数的参数列表。如果同时指 定了上面的event选项和本arguments选项,则事件对象event 对象将作为参数列表中的第一个,而其他参数排在其后。
delay:延迟执行的毫秒数(setTimeout的功能)。默认不延迟执行。如果指定
了,则调用该创建的闭包函数时将按指定的毫秒数延迟执行(调用返
回一个时间处理句柄)。
periodical:间隔执行的毫秒数(setInterval的功能)。默认不进行间隔执行。
如果指定了,则调用该创建的闭包函数后,会每间隔指定的毫秒
数后触发执行(调用返回一个时间处理句柄)。
attempt:如果指定为true,则再创建闭包的过程中,将会使用捕捉异常,如
果无异常抛出,则返回正常的闭包函数;如果发生异常,则返回 捕捉到的异常对象。默认为false。
返回值:
(function) 根据给出可选项而创建的闭包函数
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function myClass(){ alert('X:' + event.clientX); } function a(){ alert('Base...'); } var b = a.create({'event':myClass}); //按下按钮后,将先alert出如"X:33",接着alert function a(p1,p2){ alert(this.getTime()); alert(p1+'||'+p2); } var b = a.create({'bind':new Date(),'arguments':[100,200]}); b(); //alert出如"1251623399156" //alert出"100||200 |
Function.pass
返回指定了携带参数和绑定this对象的闭包函数
作用:
create的功能简化版。实现的即是create中选项’arguments’的功能。
用法:
Function.pass(arguments, bind)
返回值:
(function) 生成的闭包函数
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var myFunction = function(){ var result = 'Passed: '; for (var i = 0, l = arguments.length; i < l; i++){ result += (arguments[i] + ' '); } return result; } var myHello = myFunction.pass('hello'); var myItems = myFunction.pass(['peach', 'apple', 'orange']); //执行生成的闭包函数: alert(myHello()); //显示 Passed: hello alert(myItems()); //显示 Passed: peach apple orange |
Function.bind
重新绑定函数中this所引用的对象
作用:
create的功能简化版。实现的即是create中选项’bind’的功能。
用法:
myFunction.bind([bind[, args[, evt]]]);
返回值:
(function) 重新绑定后的函数
Example:
1 2 3 4 5 6 7 8 9 10 11 | function myFunction(){ this.setStyle('border', '1px solid black'); /*note that 'this' here refers to myFunction, not an element we'll need to bind this function to the element we want to alter*/ }; /*bind the element I want to effect to the function note that a function is returned, not executed.*/ var myBoundFunction = myFunction.bind($('bindExample')); /*execute that new function with the bound object*/ myBoundFunction(); |
Function. bindWithEvent
重新绑定函数中this所引用的对象,并向函数参数传递event对象(该方法生成的函数通常用作事件监听函数)
一般和Element:addEvent配合使用
作用:
create的功能简化版。实现的即是create中选项’bind’以及’event’为true时的功能。
用法:
myFunction.bindWithEvent([bind[, args[, evt]]]);
返回值:
(function) 重新绑定后的函数
Example:
1 2 3 4 5 6 7 8 9 | function myFunction(e, add){ //注意: 当前'this'引用的对象是window对象 //以下的语句在真正使用的时候,必须绑定一个Element对象 this.setStyle('top', e.client.x + add); }; $(myElement).addEvent('click', myFunction.bindWithEvent(myElement, 100); //当myElement的点击事件触发时, 元素的位置移动到'当前鼠标位置 + 100'处 |
Function.delay
延迟执行函数
作用:
create的功能简化版,并且创建闭包函数后执行。实现的即是create中选 ‘delay’的功能。
用法:
var timeoutID = myFunction.delay([delay[, bind[, args]]]);
返回值:
(number) 定时器引用(用于清除这个定时器时使用)
Example:
1 2 3 4 5 6 7 8 9 10 11 | var myFunction = function(){ alert('moo! Element id is: ' + this.id); }; //等待50毫秒后执行 myFunction.delay(50, myElement); //显示: 'moo! Element id is: ... ' //匿名函数的延迟执行 function(){ alert('one second later...'); }.delay(1000); |
Function.periodical
以指定的间隔反复执行函数. 可使用$clear来停止执行
作用:
create的作用简化版,并且创建闭包函数后执行。实现的即是create中选 ‘periodical’的作用。
用法:
var intervalID = myFunction.periodical([period[, bind[, args]]]);
返回值:
(number) 定时器引用(用于清除这个定时器时使用)
Example:
1 2 3 4 5 | var Site = { counter: 0 }; var addCount = function(){ this.counter++; }; addCount.periodical(1000, Site); |
Function.run
根据指定的参数和this绑定来执行函数
作用:
用法:
var myFunctionResult = myFunction.run(args[, bind]);
返回值:
(mixed) 函数执行后的返回值
Example:
简单执行:
1 2 3 4 5 6 | var myFn = function(a, b, c){ return a + b + c; } var myArgs = [1,2,3]; myFn.run(myArgs); //返回: 6 |
绑定this执行:
1 2 3 4 5 | var myFn = function(a, b, c) { return a + b + c + this; } var myArgs = [1,2,3]; myFn.run(myArgs, 6); //返回: 12 (绑定后,myFn里的this值为6) |