[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 原生函數