[TOC]
## 7.1 函数概述
### 7.1.1 函数声明(定义)
**1. JavaScript有三种方法,可以声明一个函数。**
* **function命令**
function命令声明的代码区块,就是一个函数。格式为:`function 函数名(参数){ 函数体 }`
~~~
function print(s) {
console.log(s);
}
~~~
上面的代码命名了一个print函数,以后使用print()这种形式,就可以调用相应的代码。这叫做**函数的声明(Function Declaration)。**
* **函数表达式**
除了用function命令声明函数,还可以采用变量赋值的写法。
~~~
var print = function(s) {
console.log(s);
};
~~~
这种写法将一个匿名函数赋值给变量。这时,这个匿名函数又称函**数表达式(Function Expression)**,因为赋值语句的等号右侧只能放表达式。
采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
* **Function构造函数**
Function()函数定义还可以通过Function()构造函数来定义
~~~
var f=new Function('x','y','return x+y');
等价于
var f=function(x,y){
return x+y;
}
~~~
除了最后一个参数是函数体外,前面的其他参数都是函数的形参。如果函数不包含任何参数,只须给构造函数简单的传入一个字符串---函数体---即可。 不过,Function()构造函数在实际编程中很少会用到。
注意:根据ECMAScript的规范,不得在**非函数的代码块**中声明函数,最常见的情况就是if和try语句。
**2. 函数声明提升**
就像变量的“被提前”一样,函数声明语句也会“被提前”到外部脚本或外部函数作用域的顶部,所以以这种方式声明的函数,可以被在它定义之前出现的代码所调用。
~~~
f()
function f(){}
其实JavaScript是这样解释的:
function f(){}
f()
~~~
注意:在函数提升中,函数体也会跟着提升(不像变量一样,只会提升变量声明),这也是我们可以引用后面声明的函数的原因。
此外,以表达式定义的函数并没有“被提前”,而是以变量的形式“被提前”。
~~~
f();
var f = function (){};
// TypeError: f is not a function
~~~
变量其实是分为声明,赋值两部分的,上面的代码等同于下面的形式
~~~
var f;
f();
f = function() {};
~~~
调用f的时候,f只是被声明了,还没有被赋值,等于undefined,所以会报错。
### 7.1.2 函数命名
任何合法的JavaScript标识符都可以用做一个函数的名称。
函数名称通常是动词或以动词为前缀的词组。 通常函数名的第一个字符为小写。当函数名包含多个单词时,可采取下划线法,比如:like_this();也可以采取**驼峰法**,也就是除了第一个单词之外的单词首字母使用大写字母,比如:likeThis();
### 7.1.3 函数调用
构成函数主体的JavaScript代码在定义时并不会执行,只有调用该函数,它们才会执行。
有4种方式调用JavaScript函数
**1.函数名调用**
函数可以通过函数名来调用,后跟一对圆括号和参数(圆括号中的参数如果有多个,用逗号隔开)
~~~
function test(){};
test();
~~~
**2.方法调用**
~~~
var o = {
f: function(){}
}
o.f();
~~~
**3. 构造函数调用**
如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。 凡是没有形参的构造函数调用都可以省略圆括号(但不推荐)。
~~~
var o=new Object();
var o=new Object;
~~~
**4.通过它们的call()和apply()方法间接调用**
### 7.1.4 函数参数
**查看3.7节**
### 7.1.5 递归
递归函数是在一个函数中通过名字调用资深的情况下构成的
~~~
function factorial(num)[
if (num <= 1){
return 1;
}else{
return num * factorial(num - 1);
}
}
~~~
`arguments.callee`是一个指向正在执行的函数的指针,可用于实现对函数的递归调用。
~~~
function factorial(num)[
if (num <= 1){
return 1;
}else{
return num * arguments.callee(num - 1);
}
}
~~~
严格模式下,不能访问arguments.callee,可以使用**命名函数表达式**来达成结果。
~~~
var factorial = (function f(num)[
if (num <= 1){
return 1;
}else{
return num * f(num - 1);
}
});
~~~
- 前言
- 第一章 JavaScript简介
- 第三章 基本概念
- 3.1-3.3 语法、关键字和变量
- 3.4 数据类型
- 3.5-3.6 操作符、流控制语句(暂略)
- 3.7函数
- 第四章 变量的值、作用域与内存问题
- 第五章 引用类型
- 5.1 Object类型
- 5.2 Array类型
- 5.3 Date类型
- 5.4 基本包装类型
- 5.5 单体内置对象
- 第六章 面向对象的程序设计
- 6.1 理解对象
- 6.2 创建对象
- 6.3 继承
- 第七章 函数
- 7.1 函数概述
- 7.2 闭包
- 7.3 私有变量
- 第八章 BOM
- 8.1 window对象
- 8.2 location对象
- 8.3 navigator、screen与history对象
- 第九章 DOM
- 9.1 节点层次
- 9.2 DOM操作技术
- 9.3 DOM扩展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件处理程序
- 10.3 事件对象
- 10.4 事件类型
- 第十一章 JSON
- 11.1-11.2 语法与序列化选项
- 第十二章 正则表达式
- 12.1 创建正则表达式
- 12.2-12.3 模式匹配与RegExp对象
- 第十三章 Ajax
- 13.1 XMLHttpRequest对象
- 你不知道的JavaScript
- 一、作用域与闭包
- 1.1 作用域
- 1.2 词法作用域
- 1.3 函数作用域与块作用域
- 1.4 提升
- 1.5 作用域闭包
- 二、this与对象原型
- 2.1 关于this
- 2.2 全面解析this
- 2.3 对象
- 2.4 混合对象“类”
- 2.5 原型
- 2.6 行为委托
- 三、类型与语法
- 3.1 类型
- 3.2 值
- 3.3 原生函数