javascript 函数使用说明


Posted in Javascript onApril 07, 2010

什么是函数(Function)
function sum(a,b){ 
     return a+b; 

其实通俗的说就是一个有名称的代码段,方便重用。
要注意的是:
1.Javascript 的函数语法,因为Javascript本身就是区分大小写的,所以function不能写作Function或FUNCTION.
2.sum是函数的名称,这个并不是必须的,等以后我们会说到。
3.return是返回,如果不写的话,函数的返回是undefined.如果要返回多个值,可以返回个数组或者对象(以后再说)
函数的调用

下面我们讲函数的基本调用。

var result = sum(1,2) 
函数的参数

不好意思的说,这个才是本篇文章的重点。
实例一,参数少于 实际定义参数的数目
var result = sum(1); 
结果result 为NaN,这就说明了,参数b的值为undefined,但并不会报错,这就无形中制造了bug.
实例二,参数多于 实际定义参数的数目
sum(1,2,3,4,5) 
结果为3.发现多于的参数被忽略了。
实例三,没有参数的函数
function args(){return arguments;} 
每个函数里都有一个默认的数组那就是arguments .它就是每个函数默认的参数为[] 。如果我们调用函数如下
args(1,2,3,4,5,6); 
会发现arguments的值为[1,2,3,4,5,6]。这下容易了,我们可以改造下上面的sum方法

function sum(){ 
    var res= 0; 
    for(i=0;i<arguments.length;i++){ 
        res+=arguments[i]; 
    } 
    return res; 

sum(1,2,3,4); 
结果为10,这个sum函数灵活多了吧。^_^

Functions are data

这一篇是函数里比较重要的概念,那就是函数是一个数据。看个例子
function f(){return 1;} 
var f=function(){return 1;} 
这两个函数定义都是相同的。
typeof f; 
f的值为"function",所以说Javascript 的 函数是个数据类型。它有比较两个重要的特点
1.它包含了代码
2.能被执行
看个例子
var sum = function(a,b){return a+b;} 
var add = sum; 
sum=undefined; 
typeof sum; 
typeof add; 
add(1,2); 
我们把函数sum做为一个值赋给了add,发现删除了sum不影响add的调用。所以函数也就是个正常的赋值。
匿名函数(Anonymous Functions)
Javascript中,可以不用写赋值的代码,如
"abcd" 1 [1,2,3] 
这样都不会报错,这些数据叫做匿名的。同样的函数做为数据也可以是匿名的
function(a){return a} 
匿名函数的作用有两个
1.可以把匿名函数做为一个参数传入到另一个函数中。
2.你可以理解运行这个匿名函数
下面就会详细讨论这两个功能的作用了。

回调函数(Callback Functions)

因为函数和其他数据一样可以被赋值,删除,拷贝等,所以也可以把函数作为参数传入到另一个函数中。
实例一
function invoke_and_add(a,b){ 
  return a()+b(); 

function one(){ 
  return 1; 

function two(){ 
  return 2; 

invoke_and_add(one ,two); 
结果为3;
再来看看匿名函数的用法。
实例二
invoke_and_add(function(){return 1;},function(){return 2;}),直接一个函数体传进去,没有函数名。
我们称,invoke_and_add为回调函数 
我们用匿名函数替代了 one,two两个函数。
通过上面两个实例,回调函数的定义为:传递一个函数A到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。 说白了,就是被人直接调用的函数,在一个函数执行另一个函数!
如果没有名称,就叫做匿名回调函数

回调函数的作用

主要有三个
1.当函数作为参数传递的时候,不用为这个函数定义一个名称,这样的好处是减少了全局变量。
2.节省了大量的代码。
3.提高了程序的性能。

自调用函数(Self-invoking Functions)

自调用函数也是匿名函数的一种表现形式,这个函数在定义之后,直接调用。如下

function(){ 
   alert('haha'); 

)() 

看起来还挺怪异,不过确实很简单。
自调用函数很方便使用,可以不用定义更多的全局变量。还有个好处,就是这个函数不能被执行两遍。真是非常适合做初始化的工作。
许多著名的javascript库特别多的源码中使用了这个功能,例如本人喜欢的Jquery.

内部函数(Inner Functions)

把函数作为一个值来思考一下,既然一个值可以定义在函数中,把函数做为数据放在函数中也未尝不可。如下:
function a(param){ 
function b(theinput){        
   return theinput *2; 

return 'The result is '+b(param); 

也可以这么写
var a = function(param){ 
     var b = function(theinput){ 
        return theinput*2; 
     }; 
     return 'The result is '+b(param); 
}; 
b函数是在a函数之中的 ,也就是意味着,在a函数的外部是无法访问b函数的。所以也称之为私有函数(private function)
a(2); 
a(8); 
b(2); 
发现b(2)是没有定义的。也就确定了它确实是私有函数。
内部函数的是使用还是有很多好处的。
1.可以有更少的全局变量。过多的使用全局变量就有可能由于命名冲突而产生过多的bugs
2.私有性,可以设计更好的接口函数供外部访问。

返回值为函数的函数(Functions that Return Functions)

在前几篇文章已经介绍了函数要有返回值,即使没有写return,函数也会返回一个undefine。
接下来看看返回值为函数的情况
function a(){ 
alert('a'); 
return function(){ 
  alert('b'); 
}; 

在这个例子中,a函数执行了alert('a'),以及它返回了另一个函数b。关于返回b的调用我们可以这样来用。
var newFunc = a(); 
newFunc(); 
执行结果为 alert a和alert b
如果不想赋值调用这个函数也可以简写如下
a()(); 
函数的自身重写

因为函数可以返回一个函数,那就意味着可以用一个新的函数替代一个旧的函数,根据前一个例子来改进一下
a=a(); 
第一次运行函数a,就alert a,再次运行函数a,就alert b,这个功能对初始化非常有用。这个函数a重写了自己,避免在以后调用初始化的功能(上个例子为alert a)。
当然我们还有更简单的方法来重写a函数那就是在a函数的内部重写它,来看看代码
function a(){ 
alert("a") 
a=function(){ 
   alert("b"); 


只有在初次调用a函数才会执行 alert a 在以后的调用中,都会执行alert b
下面结合前几节看个综合的例子
var c = function(){ 
   function a(){ 
    alert('a') 
   } 
   function b(){ 
    alert('b') 
   } 
   a(); 
   return b; 
}();//alert('a'); 
c();//alert('b'); 
这个例子有以下几点需要注意
1. a函数,b函数是内部函数。
2. return b 返回的是个函数的引用。
3. 子调用函数重写了函数c。

如果能明白这个例子,关于内部函数,子调用函数和返回值为函数的函数就可以都理解了。

闭包(Closures)闭包属于比较难的一部分,在学习闭包之前,先来学习以下Javascript的作用域(Scope)

作用域链(Scope Chain)

函数内部定义的变量,在函数外不能访问,或者变量定义在代码段中(如if,for中),在代码段之外也不可访问。
var a =1; 
function f(){ 
var b=1; 
return a; 

f();//a=1 
b;//b 没有定义 
a 是全局变量,而b定义在函数f之中。所以:
在f函数中,a和b都可以访问。
在f函数之外,a可以访问,而b不可以

再次看个例子
var a = 1; 
function f(){ 
var b = 1; 
function n(){ 
  var c =3; 


如果定义一个函数n在函数f中,函数n不但可以访问自己作用域的c,而且还能访问所谓的父作用域的b和a
这就是作用域链(Scope Chain)
词法作用域(Lexical Scope)

在Javascript中,也有词法作用域(Lexical Scope),这个意思是,函数在定义的时候就生成了它的作用域,而不是在调用的时候,看个例子就明白了。
function f1(){var a=1;f2();} 
function f2(){return a;} 
f1();//a没有定义 
先看看函数f1,调用了函数f2,因为函数局部变量a也在f1中,可能期望函数f2也访问a,但事实却不是这样。
因为这个时候f2函数已经定义完毕了,而它的范围没有a被找到。不管是函数f1还是函数f2,仅仅能访问的是本身的局部变 量或者全局变量。

用闭包来破坏这个作用域链(Breaking the Chain with Closure)

让我们举例来说明闭包吧。
实例1

function f(){ 
var b="b"; 
return function(){ 
  return b; 


函数f包含了变量b,在全局作用域中不可能访问b,结果为没有定义(undefined)。
看看这个函数的返回值为一个函数。这个新的函数可以访问f范围中的变量b。看如下代码
var n = f(); 
n();//访问b 
由于函数f本身就是全局的,而它返回的函数又是个新的全局函数,而它又可以访问函数f的作用域。

实例2
这个例子和上个例子结果是一样的,但是有一点不同,函数f并不返回一个函数,而是新建一个全局变量n,代码如下
var n; 
function f(){ 
var b = "b"; 
n=function(){ 
  return b; 


所以可以直接n()来访问函数f里的变量b

通过上面两个例子我们就可以说当一个函数指向了它的父作用域,其作用是指向局部变量,就可以称之为闭包。
闭包其实就提供了一个借口,一个让外部访问内部的变量的方法

当我们创建了个传递参数的函数f,这个参数就变成了函数f的局部变量了。我们可以创建一个f的内部函数来返回这个参数
function f(arg){ 
var n =function(){ 
   return args; 

  arg++; 
return n; 

var m= f(123); 
m();//124 

闭包在循环中的应用

再循环中很容易引起一些bug,虽然表面是正常的。
看如下的代码
function f(){ 
    var a = []; 
    var i; 
    for(i=0;i<3;i++){ 
        a[i] = function(){ 
            alert(i); 
            return i; 
        } 
    } 
    return a; 

var a= f(); 
a[0]();//3 
a[1]();//3 
a[2]();//3 
新建个循环,我们的目的是每次循环都新建一个函数,函数返回的是循环的序列值也就是i。我们看看以上代码的运行结果
都是为3.而我们期望的结果是1,2,3。
到底是为什么呢?我们新建了三个闭包,都指向了变量i。闭包并没有记住变量i的值,它仅是变量i的引用。在循环结束后,i的值是3,所以结果都是3了。

来看看正确的写法
function f() { 
  var a = []; 
  var i; 
  for(i = 0; i < 3; i++) { 
    a[i] = (function(x){ 
      return function(){ 
        alert(x); 
        return x; 
      } 
    })(i); 
  } 
  return a; 

var a = f(); 
a[0]();//0 
a[1]();//1 
a[2]();//2 
我们又用了一个闭包,把变量i变成了局部变量x了,x变量每次都是不同的值了。如果没有彻底理解自调用函数那就如下写法就可以明白了
function f() { 
  function makeClosure(x) { 
    return function(){ 
      return x; 
    } 
  } 
  var a = []; 
  var i; 
  for(i = 0; i < 3; i++) { 
    a[i] = makeClosure(i);  //makeClosure,用来记忆i的值。
  } 
  return a; 

Javascript 相关文章推荐
Javascript结合css实现网页换肤功能
Nov 02 Javascript
2010年最佳jQuery插件整理
Dec 06 Javascript
Jquery动态替换div内容及动态展示的方法
Jan 23 Javascript
JavaScript判断前缀、后缀是否是空格的方法
Apr 15 Javascript
超漂亮的Bootstrap 富文本编辑器summernote
Apr 05 Javascript
prototype.js常用函数详解
Jun 18 Javascript
概述VUE2.0不可忽视的很多变化
Sep 25 Javascript
超全面的JavaScript开发规范(推荐)
Jan 21 Javascript
最常见和最有用的字符串相关的方法详解
Feb 06 Javascript
详解RequireJS按需加载样式文件
Apr 12 Javascript
Vue.js 点击按钮显示/隐藏内容的实例代码
Feb 08 Javascript
vue自定义底部导航栏Tabbar的实现代码
Sep 03 Javascript
js下获取div中的数据的原理分析
Apr 07 #Javascript
Exjs 入门篇
Apr 07 #Javascript
javascript window.opener的用法分析
Apr 07 #Javascript
JS的反射问题
Apr 07 #Javascript
Extjs在exlipse中设置自动提示的方法
Apr 07 #Javascript
JavaScript Distilled 基础知识与函数
Apr 07 #Javascript
javascript setTimeout()传递函数参数(包括传递对象参数)
Apr 07 #Javascript
You might like
javascript some()函数用法详解
2014/11/13 PHP
PHP实现原比例生成缩略图的方法
2016/02/03 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
PHP实现微信退款功能
2018/10/02 PHP
PHP常用正则表达式精选(推荐)
2019/05/28 PHP
ThinkPHP 5.x远程命令执行漏洞复现
2019/09/23 PHP
mouse_on_title.js
2006/08/25 Javascript
javascript:void(0)使用探讨
2013/08/27 Javascript
JS获取计算机mac地址以及IP的实现方法
2014/01/08 Javascript
JS实现将人民币金额转换为大写的示例代码
2014/02/13 Javascript
JavaScript中的单引号和双引号报错的解决方法
2014/09/01 Javascript
JS的框架Polymer中的dom-if和is属性使用说明
2015/07/29 Javascript
jquery+CSS实现的多级竖向展开树形TRee菜单效果
2015/08/24 Javascript
全面解析JS字符串和正则表达式中的match、replace、exec等函数
2016/07/01 Javascript
JavaScript中数组slice和splice的对比小结
2016/09/22 Javascript
解析NodeJs的调试方法
2016/12/11 NodeJs
详谈jQuery Ajax(load,post,get,ajax)的用法
2017/03/02 Javascript
JavaScript使用atan2来绘制箭头和曲线的实例
2017/09/14 Javascript
JS中精巧的自动柯里化实现方法
2017/12/12 Javascript
angularjs实现分页和搜索功能
2018/01/03 Javascript
基于JS开发微信网页录音功能的实例代码
2019/04/30 Javascript
vue 实现Web端的定位功能 获取经纬度
2019/08/08 Javascript
微信小程序实现点击空白隐藏的方法示例
2019/08/13 Javascript
JavaScript 预解析的4种实现方法解析
2019/09/03 Javascript
解决vue与node模版引擎的渲染标记{{}}(双花括号)冲突问题
2020/09/11 Javascript
详解python中的Turtle函数库
2018/11/19 Python
Python人脸识别第三方库face_recognition接口说明文档
2019/05/03 Python
Python中使用__new__实现单例模式并解析
2019/06/25 Python
让Python脚本暂停执行的几种方法(小结)
2019/07/11 Python
python生成requirements.txt的两种方法
2019/09/18 Python
个人简历自我评价八例
2013/10/31 职场文书
小学门卫岗位职责
2013/12/17 职场文书
视光学毕业生自荐书范文
2014/02/13 职场文书
党支部半年考察意见
2015/06/01 职场文书
《1942》观后感
2015/06/08 职场文书
Spring Boot DevTools 全局配置学习指南
2022/03/31 Java/Android