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 相关文章推荐
语义化 H1 标签
Jan 14 Javascript
修改jquery.lazyload.js实现页面延迟载入
Dec 22 Javascript
解析JSON对象与字符串之间的相互转换
Dec 18 Javascript
js星星评分效果
Jul 24 Javascript
jquery zTree异步加载简单实例讲解
Feb 25 Javascript
JS实现图文并茂的tab选项卡效果示例【附demo源码下载】
Sep 21 Javascript
React Native AsyncStorage本地存储工具类
Oct 24 Javascript
基于casperjs和resemble.js实现一个像素对比服务详解
Jan 10 Javascript
如何解决vue2.0下IE浏览器白屏问题
Sep 13 Javascript
详解angular2.x创建项目入门指令
Oct 11 Javascript
基于js实现逐步显示文字输出代码实例
Apr 02 Javascript
JS中队列和双端队列实现及应用详解
Sep 29 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
Amazon Prime Video平台《无限住人 -IMMORTAL-》2020年开始TV放送!
2020/03/06 日漫
PHP中通过ADO调用Access数据库的方法测试不通过
2006/12/31 PHP
一个好用的PHP验证码类实例分享
2013/12/27 PHP
php获取网页标题和内容函数(不包含html标签)
2014/02/03 PHP
php7安装mongoDB扩展的方法分析
2017/08/02 PHP
Laravel 集成微信用户登录和绑定的实现
2019/12/27 PHP
javascript编程起步(第六课)
2007/02/27 Javascript
Tab切换组件(选项卡功能)实例代码
2013/11/21 Javascript
实例解析jQuery插件EasyUI最常用的表单验证规则
2015/11/29 Javascript
带有定位当前位置的百度地图前端web api实例代码
2016/06/21 Javascript
Jquery实现遮罩层的简单实例(就是弹出DIV周围都灰色不能操作)
2016/07/14 Javascript
js中遍历Map对象的简单实例
2016/08/08 Javascript
详解Vue-基本标签和自定义控件
2017/03/24 Javascript
vue2.0s中eventBus实现兄弟组件通信的示例代码
2017/10/25 Javascript
jQuery实现的电子时钟效果完整示例
2018/04/28 jQuery
JavaScript实现图片合成下载的示例
2020/11/19 Javascript
vue+element实现动态加载表单
2020/12/13 Vue.js
[02:32]DOTA2完美大师赛场馆静安体育中心观赛全攻略
2017/11/08 DOTA
使用Python获取CPU、内存和硬盘等windowns系统信息的2个例子
2014/04/15 Python
Python编写生成验证码的脚本的教程
2015/05/04 Python
在Python的Django框架中编写错误提示页面
2015/07/22 Python
Python中字符串的格式化方法小结
2016/05/03 Python
Python 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)
2018/03/19 Python
多个应用共存的Django配置方法
2018/05/30 Python
django+echart数据动态显示的例子
2019/08/12 Python
opencv python在视屏上截图功能的实现
2020/03/05 Python
python3排序的实例方法
2020/10/20 Python
浅析border-radius如何兼容IE
2016/04/19 HTML / CSS
全球地下的服装和态度:Slam Jam
2018/02/04 全球购物
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
学校门卫管理制度
2014/01/30 职场文书
应届毕业生通用的自荐书范文
2014/02/07 职场文书
授权委托书怎么写
2014/09/25 职场文书
学院党委班子四风问题自查报告及整改措施
2014/10/25 职场文书
房产公证书样本
2015/01/23 职场文书
大学校园招聘会感想
2015/08/10 职场文书