javascript中函数用法介绍(匿名函数,函数传值,参数)
下面要来介绍关于js函数的常用的一些函数的定义与用法。
第一课 —— 匿名函数
一、什么是匿名函数?
在Javascript定义一个函数一般有如下三种方式:
1.函数关键字(function)语句,代码如下:
- function fnMethodName(x){alert(x);}
2.函数字面量(Function Literals):
- var fnMethodName = function(x){alert(x);}
3.Function()构造函数:
- var fnMethodName = new Function('x','alert(x);')
上面三种方法定义了同一个方法函数fnMethodName,第1种就是最常用的方法,后两种都是把一个函数复制给变量fnMethodName,而这个函数是没有名字的,即匿名函数。实际上,相当多的语言都有匿名函数。
二、函数字面量和Function()构造函数的区别
1.虽然函数字面量是一个匿名函数,但语法允许为其指定任意一个函数名,当写递归函数时可以调用它自己,使用Function()构造函数则不行,代码如下:
- var f = function fact(x) {
- if (x < = 1) return 1;
- else return x*fact(x-1);
- };
2.Function()构造函数允许运行时Javascript代码动态的创建和编译。在这个方式上它类似全局函数eval()。
3.Function()构造函数每次执行时都解析函数主体,并创建一个新的函数对象,所以当在一个循环或者频繁执行的函数中调用Function()构造函数的效率是非常低的。相反,函数字面量却不是每次遇到都重新编译的。
4.用Function()构造函数创建一个函数时并不遵循典型的作用域,它一直把它当作是顶级函数来执行,代码如下:
- var y = "global";
- function constructFunction() {
- var y = "local";
- return new Function("return y"); // 无法获取局部变量
- }
- alert(constructFunction()()); // 输出 "global"
和函数关键字定义相比Function()构造器有自己的特点且要难以使用的多,所以这项技术通常很少使用。而函数字面量表达式和函数关键字定义非常接近。考虑前面的区别,虽然有消息说字面量的匿名函数在OS X 10.4.3下的某些webkit的引擎下有bug,但我们平常所说的匿名函数均指采用函数字面量形式的匿名函数。更多详细内容可以阅读《JavaScript: The Definitive Guide, 5th Edition》的Functions那章。
三、匿名函数的代码模式
昨天hedger wang在他的blog介绍了几种匿名函数的代码模式.
错误模式:其无法工作,浏览器会报语法错,代码如下:
- function(){
- alert(1);
- }();
1.函数字面量:首先声明一个函数对象,然后执行它。
- (function(){
- alert(1);
- } ) ( );
2.优先表达式:由于Javascript执行表达式是从圆括号里面到外面,所以可以用圆括号强制执行声明的函数。
- ( function(){
- alert(2);
- } ( ) );
3.Void操作符:用void操作符去执行一个没有用圆括号包围的一个单独操作数。
- void function(){
- alert(3);
- }()
这三种方式是等同的,hedger wang因为个人原因比较喜欢第3种,而在实际应用中我看到的和使用的都是第1种。
四、匿名函数的应用
1.《Javascript的一种模块模式》中的第一句话就是“全局变量是魔鬼”。配合var关键字,匿名函数可以有效的保证在页面上写入Javascript,而不会造成全局变量的污染。这在给一个不是很熟悉的页面增加Javascript时非常有效,也很优美。实际上,YUI以及其相应的范例中大量使用匿名函数,其他的Javascript库中也不乏大量使用。
2.Javascript的函数式编程(functional programming)的基石
第二课 – 函数作为值
事实上,我们一般在JavaScript中声明函数的方式可以看作是一个简化了的语法(也就是语法糖,syntactic sugar).
例,下面两个表达式其实完全一样,所以左边的表达式仅仅是右边的简写,代码如下:
- function average(x,y) {
- return (x+y)/2;
- }
- alert( average(1,3) );
- var average = function(x,y) {
- return (x+y)/2;
- }
- alert( average(1,3) );
实例,代码如下:
- <html>
- <head>
- <script type="text/javascript">
- function myFunction()
- {
- return ("您好,祝您愉快!")
- }
- </script>
- </head>
- <body>
- <script type="text/javascript">
- document.write(myFunction())
- </script>
- <p>body 部分中的脚本调用一个函数。</p>
- <p>该函数返回一段文本。</p>
- </body>
- </html>
实例,代码如下:
- <html>
- <head>
- <title>Example-6.12函数参数和函数返回值</title>
- </head>
- <body>
- <script>
- <!--
- function dwn(s)
- {
- document.write(s + "<br/>");
- }
- //集合变换操作,闭包op作为参数
- function trans(list, op)
- {
- for(var i = 0; i < list.length; i++)
- {
- //根据闭包op计算每一个list[i]执行op后的结果,并用这个结果更新list[i]
- list[i] = op(list[i]);
- }
- }
- var list = [1,2,3,4];
- trans(list, function(x){return x+1});
- dwn(list); //得到2,3,4,5
- trans(list, function(x){return x*2});
- dwn(list); //因为这时候list=[2,3,4,5]所以输出的是4 ,6 ,8 ,10
- //累加器:闭包作为返回值
- function add(a, b)
- {
- bb = b || 0;
- var s = a + b;
- //返回一个供进一步累加的闭包。
- var ret = function(a){
- return add(a, s);
- }
- retret.valueOf = ret.toString = function(){
- return s;
- }
- return ret;
- }
- dwn(add(5)); //5
- dwn(add(5)(10)); //15
- dwn(add(5)(10)(20)); //35,这个闭包会执行两次
- -->
- </script>
- </body>
- </html>
输出结果是:
2,3,4,5
4,6,8,10
5
15
35
从这里可以得出一个结论,函数是一个值就像字符串、数字或数组一样。这还出现几个问题:
我是否可以把函数作为参数传递?
可以,见下面的例子。
是否可以实时生成函数?
当然了,这是一个高级的主题,它可以通过eval函数来完成。小提示:看看本页面的源代码。
例,这个例子演示了如何把函数作为参数传递,代码如下:
- var applyFun = function (f,x,y) { return f(x,y); };
- var add = function(x,y) {
- return x+y;
- };
- alert( applyFun(add,3,4) ); // 7
下面要来介绍关于js函数的常用的一些函数的定义与用法。
第三课 – 两种方式调用函数
在JavaScript中,有两种调用函数的方式,一般的方式是把参数放在括号中,如alert(42),另一种方式是同时把函数和参数都放在括号中,如(alert)(42)。
例,代码如下:
- alert(42);
- (alert) (42);
- (function(x) { alert(x-13); }) (55);
实例,作为参数的函数:
- function DoSomeSing(url)
- {
- ……
- }
- //函数作为参数
- function DealLink(aClass,funcName)
- {
- if(!document.getElementsByTagName){return;}
- var links=document.getElementsByTagName("a");
- for(var i=0;i<links.length;i++)
- {
- if(links[i].className==aClass)
- {
- links[i].onclick=function()
- {
- funcName(url);
- return false;
- }
- }
- }
- }
交付使用的函数:
- function FillOAToLink()
- {
- DealLink("aShowOA",DoSomeSing);
- }
为什么函数两边的括号很重要:如果你写了括号,那么在括号中的代码就会被先计算。在计算之后,括号所在的地方就会有一个值。这个值可能是一个字符串、一个数字或一个函数。
第四课 – “短路”条件调用
现在我们将学习如何使用“短路”条件调用,使用这个方法可以缩短源代码同时代码也变得更加可读。
例,这个语法并不是用在左表达式上,而是用在右表达式上,代码如下:
- var f = false; var t = true;var z;
- if(f)
- z = 4;
- else if(t)
- z = 2;
- alert(z);
- var f = false; var t = true;
- var z = (f && 4) || (t && 2);
- alert(z);
第五课 – 它好在哪里
OK,现在我们已经学习了一些函数式JavaScript的内容。那么它好在哪里?函数式JavaScript编程之所以很重要有三条主要的理由:
它有助于写出模块化和可服用的代码。
它对事件处理程序非常有效。
它很有趣!
在下面的篇幅中,我会给出更多关于前两条理由的信息
1. 模块化和可复用的代码
现在你已经知道如何将函数作为值使用,那么你也应该试试!一个很好的例子是数组内建的sort方法,预定义的sort()把所有的对象转换成字符串并把他们按照词语的顺序排序,但如果我们有用户自定义的对象或者数字那么它就不是很有用了,于是这个函数可以让你给他一个进行比较的函数作为参数,如sort(compareFunction),这个方法让我们甚至不用接触实际的sort方法.
例,代码如下:
- var myarray = new Array(6,7,9,1,-1);
- var sortAsc = function(x,y) { return x-y; };
- var sortDesc = function(x,y) { return y-x; };
- myarray.sort(sortDesc);
- alert(myarray);
- myarray.sort(sortAsc);
- alert(myarray);
2. 事件处理程序
对事件处理程序使用函数式编程也许是最直观的函数作为值得应用了,既然这样我们马上就演示一个例子.
简单的例子:;ie
现在有一个Button类,带一个自定义的onclick行为,代码如下:
- function Button(clickFunction) {
- this.button = document.createElement("button");
- this.button.appendChild(document.createTextNode("Press me!"));
- this.button.onclick = clickFunction;
- }
- var bt = new Button(function() { alert("42"); });
- Press me!
练习: 为什么我们要把alert包裹在一个匿名函数中?
高级例子:现在我们想改进我们的Button类,每一个按钮都被分配了一个值当按钮被点击时显示该值,首先我们调整我们的类,代码如下:
- function Button(value) {
- this.value = value;
- this.button = document.createElement("button");
- this.button.appendChild(document.createTextNode("test"));
- }
下面你也许要尝试写下面的代码:
- this.button.onclick = function() { alert(this.value); };
如果你执行它你就会发现提示框中间是空的。为什么会这样呢?其实原因在于JavaScript的可见性规则。当onclick函数被执行时this指向的是按钮的DOM节点而非自定义的按钮对象。
我们如何解决这个问题?使用函数式编程,代码如下:
- this.button.onclick = (function(v) {
- return function() { alert(v); };
- }) (this.value);
这种情况下执行该匿名函数会将v绑定到this.value上。