函数
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。ECMAScript 中的函数使用function 关键字来声明,后跟一组参数以及函数体。
函数的基本语法如下所示:

function functionName(arg0, arg1,...,argN) {
  statements
}
以下是一个函数示例:
function sayHi(name, message) {
  alert("Hello " + name + "," + message);
}

这个函数可以通过其函数名来调用,后面还要加上一对圆括号和参数(圆括号中的参数如果有多个,可以用逗号隔开)。调用sayHi()函数的代码如下所示:
sayHi("Nicholas", "how are you today?");

这个函数的输出结果是"Hello Nicholas,how are you today?"。函数中定义中的命名参数name和message 被用作了字符串拼接的两个操作数,而结果最终通过警告框显示了出来。
ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过return 语句后跟要返回的值来实现返回值。请看下面的例子:
function sum(num1, num2) {
  return num1 + num2;
}

这个sum()函数的作用是把两个值加起来返回一个结果。我们注意到,除了return 语句之外,没有任何声明表示该函数会返回一个值。调用这个函数的示例代码如下:
var result = sum(5, 10);
这个函数会在执行完return 语句之后停止并立即退出。因此,位于return 语句之后的任何代码都永远不会执行。例如:
function sum(num1, num2) {
  return num1 + num2;
  alert("Hello world"); // 永远不会执行
}
在这个例子中,由于调用alert()函数的语句位于return 语句之后,因此永远不会显示警告框。
当然,一个函数中也可以包含多个return 语句,如下面这个例子中所示:
function diff(num1, num2) {
  if (num1 < num2) {
    return num2 - num1;
  } else {
    return num1 - num2;
  }
}

这个例子中定义的diff()函数用于计算两个数值的差。如果第一个数比第二个小,则用第二个数减第一个数;否则,用第一个数减第二个数。代码中的两个分支都具有自己的return 语句,分别用于执行正确的计算。
另外,return 语句也可以不带有任何返回值。在这种情况下,函数在停止执行后将返回undefined值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下。比如在下面这个例子中,就不会显示警告框:
function sayHi(name, message) {
  return;
  alert("Hello " + name + "," + message); //永远不会调用
}

注:推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。

严格模式对函数有一些限制:
 不能把函数命名为eval 或arguments;
 不能把参数命名为eval 或arguments;
 不能出现两个命名参数同名的情况。
如果发生以上情况,就会导致语法错误,代码无法执行。

理解参数

arguments 对象只是与数组类似(它并不是Array 的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0],第二个元素是argumetns[1],以此类推),使用length 属性来确定传递进来多少个参数。在前面的例子中,sayHi()函数的第一个参数的名字叫name,而该参数的值也可以通过访问arguments[0]来获取。因此,那个函数也可以像下面这样重写,即不显式地使用命名参数:
function sayHi() {
  alert("Hello " + arguments[0] + "," + arguments[1]);
}

这个重写后的函数中不包含命名的参数。虽然没有使用name 和message 标识符,但函数的功能依旧。这个事实说明了ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的。另外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致。但在ECMAScript 中,没有这些条条框框,解析器不会验证命名参数。
通过访问arguments 对象的length 属性可以获知有多少个参数传递给了函数。下面这个函数会在每次被调用时,输出传入其中的参数个数:
function howManyArgs() {
  alert(arguments.length);
}
howManyArgs("string", 45); //2
howManyArgs(); //0
howManyArgs(12); //1

执行以上代码会依次出现3 个警告框,分别显示2、0 和1。由此可见,开发人员可以利用这一点让函数能够接收任意个参数并分别实现适当的功能。请看下面的例子:
function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 10);
  } else if (arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}
doAdd(10); //20
doAdd(30, 20); //50

函数doAdd()会在只有一个参数的情况下给该参数加上10;如果是两个参数,则将那个参数简单相加并返回结果。因此,doAdd(10)会返回20,而doAdd(30,20)则返回50。虽然这个特性算不上完美的重载,但也足够弥补ECMAScript 的这一缺憾了。
另一个与参数相关的重要方面,就是arguments 对象可以与命名参数一起使用,如下面的例子所示:
function doAdd(num1, num2) {
  if(arguments.length == 1) {
    alert(num1 + 10);
  } else if (arguments.length == 2) {
    alert(arguments[0] + num2);
  }
}

在重写后的这个doAdd()函数中,两个命名参数都与arguments 对象一起使用。由于num1 的值与arguments[0]的值相同,因此它们可以互换使用(当然,num2 和arguments[1]也是如此)。
关于arguments 的行为,还有一点比较有意思。那就是它的值永远与对应命名参数的值保持同步。
例如:

function doAdd(num1, num2) {
  arguments[1] = 10;
  alert(arguments[0] + num2);
}

每次执行这个doAdd()函数都会重写第二个参数,将第二个参数的值修改为10。因为arguments对象中的值会自动反映到对应的命名参数,所以修改arguments[1],也就修改了num2,结果它们的值都会变成10。不过,这并不是说读取这两个值会访问相同的内存空间;它们的内存空间是独立的,但它们的值会同步。另外还要记住,如果只传入了一个参数,那么为arguments[1]设置的值不会反应到命名参数中。这是因为arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。
关于参数还要记住最后一点:没有传递值的命名参数将自动被赋予undefined 值。这就跟定义了变量但又没有初始化一样。例如,如果只给doAdd()函数传递了一个参数,则num2 中就会保存undefined 值。
严格模式对如何使用arguments 对象做出了一些限制。首先,像前面例子中那样的赋值会变得无效。也就是说,即使把arguments[1]设置为10,num2 的值仍然还是undefined。其次,重写arguments 的值会导致语法错误(代码将不会执行)。

没有重载
ECMAScript 函数不能像传统意义上那样实现重载。而在其他语言(如Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScirpt函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。
如果在ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数。请看下面的例子:
function addSomeNumber(num){
  return num + 100;
}
function addSomeNumber(num) {
  return num + 200;
}
var result = addSomeNumber(100); //300

在此,函数addSomeNumber()被定义了两次。第一个版本给参数加100,而第二个版本给参数加200。由于后定义的函数覆盖了先定义的函数,因此当在最后一行代码中调用这个函数时,返回的结果就是300。

如前所述,通过检查传入函数中参数的类型和数量并作出不同的反应,可以模仿方法的重载。

《JavaScript高级程序设计》读书笔记 ---函数的更多相关文章

  1. 《JavaScript高级程序设计》读书笔记--前言

    起因 web编程过程使用javascript时感觉很吃力,效率很低.根本原因在于对javascript整个知识体系不熟,看来需要找些书脑补一下,同时欢迎众网友监督. 大神推荐书籍 看了博客大神们推荐的 ...

  2. 《Javascript高级程序设计》读书笔记之对象创建

    <javascript高级程序设计>读过有两遍了,有些重要内容总是会忘记,写一下读书笔记备忘 创建对象 工厂模式 工厂模式优点:有了封装的概念,解决了创建多个相似对象的问题 缺点:没有解决 ...

  3. <数据结构与算法分析>读书笔记--函数对象

    关于函数对象,百度百科对它是这样定义的: 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象.又称仿函数. 听起来确实很难懂,通过搜索我找到一篇 ...

  4. C语言学习笔记--函数

    1. C 语言中的函数 (1)函数的由来: 程序 = 数据 + 算法→C 程序 = 数据 + 函数 (2)模块化程序设计 (3)C 语言中的模块 2. 面向过程的程序设计 (1)面向过程是一种以过程为 ...

  5. 《JavaScript高级程序设计》读书笔记 ---基本概念小结

     ECMAScript 中的基本数据类型包括Undefined.Null.Boolean.Number 和String. 与其他语言不同,ECMScript 没有为整数和浮点数值分别定义不同的数据 ...

  6. C语言学习笔记--函数与指针

    1. 函数类型 (1)C 语言中的函数有自己特定的类型,这个类型由返回值.参数类型和参数个数共同决定.如 int add(int i,int j)的类型为 int(int,int). (2)C 语言中 ...

  7. 《Go程序设计语言》读书笔记-函数

    函数包含连续执行的语句,可以使用代码中通过调用函数来执行他们,函数能够将一个复杂的工作切分成多个更小的模块,使多人写作变得容易.另外,函数对他的使用者隐藏了实现细节.这几方面的特性使得函数成为多数编程 ...

  8. 《JavaScript高级程序设计》读书笔记(三)基本概念第六小节理解函数

    内容---语法---数据类型---流程控制语句 上一小节---理解函数 本小节 函数--使用function关键字声明,后跟一组参数以及函数体 function functionName(arg0, ...

  9. JavaScript高级程序设计(读书笔记)之函数表达式

    定义函数的方式有两种:一种是函数声明,另一种就是函数表达式. 函数声明的一个重要特征就是函数声明提升(function declaration hoisting),意思是在执行代码前会先读取函数声明. ...

随机推荐

  1. sim808模块收发送短信

    一,简介 SIM 808发送短信分text模式和PDU模式.text模式已ascii码发送短信,这种模式比较简单,发送命令AT+CMGF=1就可以发送短信,而PDU模式比较复杂,首先发送命令AT+CM ...

  2. com.google.common.collect.Lists#transform使用注意

    /** * Returns a list that applies {@code function} to each element of {@code * fromList}. The return ...

  3. Linux Yum仓库介绍及服务端及客户端配置

    YUM服务器 适合在于内网使用,因为很多包需要国外的网站下载应用包,这样网络很不稳定 下载慢,所有为何不尝试搭建 自己内部的YUM服务器呢 YUM服务器搭建 一 创建yum仓库目录 #mkdir -p ...

  4. python 基础学习2--编程

    python编程的步骤为: __name__ 指示模块如何被加载:如果模块被导入,__name__的值是模块的名称,如果模块被直接执行,__name__的值是main 变量不用进行声明,直接赋值:无需 ...

  5. 字符串ID转换成字符串名字

    select  U.CnName+','  from f_splitstr('1828,1055333,1,1035681,752,494,22549,219,23860,478,23453,677, ...

  6. [Rails] 从 Request 到 Response(1)

    本文翻译自:Rails from Request to Response 系列:个人选择了自己感兴趣的部分进行翻译,需要阅读原文的同学请戳前面的链接. 第一部分 导言(Introduction) 服务 ...

  7. IP地址接口小结

    1 百度http://api.map.baidu.com/location/ip?ak=F454f8a5efe5e577997931cc01de3974&ip=58.67.143.169 {& ...

  8. java基础之操作符

    一:赋值 1.对基本数据类型的赋值,int a=b:   //把b的值复制给a,如果修改了a的值,b 的值不会受到影响. 2.对引用类型的赋值, public class Text { public ...

  9. Jmeter:相应断言介绍

    Jmeter进行性能测试时,作为对上一个请求返回信息的校验,基本上断言是不可少的,今天主要介绍一下Jmeter的相应断言校验. 相应断言:即对服务器相应信息的校验判断,发送http请求后,对服务器返回 ...

  10. js-数组算法收集版(转)

    不管是在面试中还是在笔试中,我们都会被经常问到关于javascript数组的一些算法,比方说数组去重.数组求交集.数组扰乱等等.今天抽点时间把javascript中的一些常用的数组算法做一下总结,以方 ...