函數是一組可以隨時隨地運行的語句,函數作為ECMAScript的核心是很重要的。函數是由事件驅動的或者當它被調用時執行的可重復使用的代碼塊。也就是函數是定義一次但卻可以調用或執行任意多次的一段JavaScript代碼。函數有時會有參數,即函數被調用時指定了值的局部變量。函數常常使用這些參數來計算一個返回值,這個值也成為函數調用表達式的值。
### 一,函數聲明
函數對于任何語言來說都是一個核心的概念。通過函數可以封裝任意多條語句,而且可以在任何地方,任何時候調用執行。JS中的函數使用function關鍵字來聲明,后跟一組參數以及函數體。
函數的基本語法是這樣的:
~~~
<span style="font-size:18px;">function functionName(arg0, arg1, ... argN) {
statements
}</span>
~~~
ECMAScript規定的函數聲明方式有三種:
(1)普通函數聲明
~~~
<span style="font-size:18px;">function box(num1,num2){
return num1+num2;
}</span>
~~~
(2)使用變量初始化什聲明函數
~~~
<span style="font-size:18px;">var box=function(num1,num2){
return num1+num2;
}</span>
~~~
(3)使用Function構造函數聲明
~~~
<span style="font-size:18px;">vax box=new Function('num1','num2','num1+num2');</span>
~~~
### 二,函數的類型及函數的調用
ECMAScript語法規定了
(1)無參數的函數:函數的聲明的時候沒有參數,調用函數的時候直接使用即可。
~~~
function box(){
document.write("我是中國人!");
}
box();//函數調用
~~~
運行的結果為:我是中國人!
(2)帶參數的函數:函數的聲明的時候同時定義了參數變量,參數可以是多個。
~~~
function box(name,age) {
document.write("你的姓名是:"+name+"你的年齡是:"+age);
}
box("張三","24");//函數調用
~~~
運行的結果為:你的姓名是:張三
你的年齡是:24
(3)帶有返回值的函數
帶參數和無參數的函數,都沒有定義返回值,而是調用后直接執行的,實際上,任何函數都可以通過return語句跟后面的要返回的值來實現返回值
1,無參數的函數
~~~
function box(){
return "我是中國人!";
}
document.write(box());
~~~
同上面的輸出結果:我是中國人!
2,帶參數的函數
~~~
function box(name,age){
return "你的姓名是:"+name+"<br/>"+"你的年齡是:"+age;
}
document.write(box("張三","24"));//函數調用
document.write("<hr/>");
var demo=box("李四","23");//也可以重新賦值新的函數
document.write(demo);
~~~
運行的結果為:

(4)作為值的函數(比較特殊)
首先我們來看一個函數作為常規的變量的例子:
~~~
function box(sum,num){
return sum+num;//這里傳遞的是函數的返回值和普通的變量一樣
}
function sum(num){
return num+10;
}
var result=box(sum(10),10);
document.write("result="+result);
~~~
頁面的輸出結果為:result=30
下面則傳遞的是函數,仔細和上面的區分:
~~~
function box(sum,num){
return sum(num);//這里傳遞的是函數
}
function sum(num){
return num+10;
}
var result=box(sum,10);
document.write("result="+result);
~~~
頁面的輸出結果為:result=20
### 三,函數的內部屬性
在函數內部,有兩個特殊的對象:arguments對象和this對象。arguments對象是類數組對象,包含著傳入函數中的所有參數,主要用途是保存函數參數,主要的屬性有length,這個屬性是動態的判斷函數有多少個參數。但這個對象還有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數。
(1)arguments對象的length屬性
JS函數不介意傳遞進來多少參數,也不會因為參數不統一而錯誤。實際上,函數體內可以通過arguments對象來接收傳遞進來的參數。
我們先來看一個我們在函數傳遞參數遇到的問題:函數聲明時并不知道要定義多少個參數,在調用函數卻出現多出的或不足的問題。
~~~
function box(){
return arguments[0]+"|"+arguments[1];
}
document.write(box(1,2,3,4,5,6));
~~~
輸出的結果為:1|2。因此輸出的顯然與我們想要做的不符,那么怎么解決呢?
有了arguments對象的length屬性我們就能可以得到參數的數量,避免上面的錯誤出現。
~~~
function box(){
return arguments.length;
}
document.write(box(1,2,3,4,5,6));
~~~
輸出:6
我們還可以利用length屬性來智能的判斷有多少參數,然后把參數進行合理的應用,比如,實現一個加法運算,將所有傳進來的數字累加,而數字的個數又不確定。
~~~
function box(){
var sum=0;
if(arguments.length==0)
{
return sum;
}
for(var i=0;i<arguments.length;i++)
{
sum=sum+arguments[i];
}
return sum;//返回累加結果
}
document.write(box(1,2,3,4,5,6));
~~~
? ? ?輸出:21
? ? ?(2)arguments對象的callee屬性
? ? ?還是來說問題:對于遞歸的問題我們很熟悉了,JS中也不例外
~~~
function box(num){
if(num<=1)
{
return 1;
}
else
{
return num*box(num-1);//遞歸
}
}
document.write(box(4));
~~~
輸出:24
對于階乘函數一般要用到遞歸算法,所以函數內部一定對調用自身,如果函數名不改變是沒有問題的,但一旦改變函數名,內部的自身調用需要逐一修改。為了解決這個問題,可以使用arguments.callee來代替。
~~~
function box(num){
if(num<=1)
{
return 1;
}
else
{
return num*arguments.callee(num-1)//遞歸
}
}
document.write(box(4));
~~~
輸出:24
(3)this對象
函數內部另一個特殊的對象時this,其行為與Java和C#中的this大致相似,換句話說,this引用的是函數據以執行操作的對象,或者說函數調用語句所處的那個作用域。當在全局作用域中調用函數時,this對象引用的就是window(window是一個對象,是JavaScript中最大的對象,是最外圍的對象)。
~~~
var color="紅色";//這里的color是全局變量,并且這個變量是window的屬性
document.write(window.color+"<br/>");
document.write(this.color+"<br/>");
var box={
color:"藍色",//這里的color是box下的屬性,是局部變量
sayColor:function(){
return this.color;//此時的this只能是box中的color
}
};
document.write(box.sayColor()+"<br/>");//局部的
document.write(this.color);//全局的
~~~
運行的結果為:

### 四,函數屬性和方法
(1)JavaScript中的函數是對象,因此函數也有屬性和方法。每個函數都包含兩個屬性:length和prototype。其中,length屬性表示函數希望接受的命名參數的個數。
~~~
function box(num1,num2){
return num1+num2;
}
document.write(box.length);
~~~
輸出的結果;2
對于prototype屬性,它是保存所有實例方法的真正所在,也就是原型。這個屬性我們先不做過多的介紹。
prototype屬性下有兩個方法:apply()和call(),每個函數都包含這兩個非繼承而來的方法。這兩個方法的用途都在特定
的作用域中調用函數,實際上等于設置函數體內this對象的值。?
~~~
function box(num1,num2){
return num1+num2;
}
function sayBox(num1,num2){
return box.apply(this,[num1,num2]);//this表示作用域,這里是window,[]表示box所需的參數
}
function sayBox2(num1,num2){
return box.apply(this,arguments);//arguments對象表示box所需的參數
}
document.write(sayBox(10,10)+"<br/>");
document.write(sayBox2(10,10));
~~~
輸出的結果為:20
20
(2)call()方法和apply()方法延伸
call()方法和apply()方法相同,它們的區別僅僅在于接收參數的方式不同。對于call()方法而言,第一個參數是作用域,沒有變化,變化的只是其余參數都是直接傳遞給函數的。
~~~
function box(num1,num2){
return num1+num2;
}
function callBox(num1,num2){
return box.call(this,num1,num2);//區別apply()方法
}
document.write(callBox(10,10));
~~~
輸出的結果為:20
call()方法和apply()方法真正的作用是擴展函數賴以運行的作用域
~~~
var color="紅色";//全局變量
var box={
color:"藍色",//局部變量
};
function sayColor(){
return this.color;
}
document.write(sayColor()+"<br/>");//作用域在Window
document.write(sayColor.call(this)+"<br/>");//作用域在Window下
document.write(sayColor.call(window)+"<br/>");//作用域在Window下
document.write(sayColor.call(box));//作用域在box下,對象冒充
~~~
輸出的結果為:

使用call()方法或者apply()方法來擴充作用域的最大好處就是對象不需要與方法發生任何耦合關系。也就是說,box對象和sayColor()方法之間不會有多余的關聯操作,比如;box.sayColor=sayColor;
### 五,ECMAScript閉包
ECMAScrip最易讓人誤解的一點是,它支持閉包。閉包,指的是詞法表示包括不被計算的變量的函數,也就是說,函數可以使用函數之外定義的變量。
其實我在前面的博文已經使用到了閉包,比如在[輕松學習JavaScript七:JavaScript的流程控制語句](http://blog.csdn.net/erlian1992/article/details/50098575)中使用的變量time就是全局變量,函數myFunction()使用這個全局變量,并不是函數本身定義的。還是看一下那個實例吧:
~~~
var time=new Date().getHours();
document.write("當前北京時間:"+time);
function myFunction()
{
var x="";
if (time<20)
{
x="Good day";
}
document.getElementById("demo").innerHTML=x;
}
~~~
(1)簡單的閉包實例
在ECMAScript中使用全局變量是一個簡單的閉包實例。請思考下面這段代碼輸出的結果是什么:
~~~
var sMessage = "hello world";
function sayHelloWorld() {
document.write(sMessage);
}
sayHelloWorld();
~~~
在上面這段代碼中,腳本被載入內存后,并沒有為函數sayHelloWorld()計算變量sMessage的值。該函數捕?sMessage的值只是為了以后的使用,也就是說,解釋程序知道在調用該函數時要檢查sMessage的值。sMessage將
在函數調用sayHelloWorld()是在(最后一行)被賦值,顯示消息"hello world"。
(2)復雜的閉包實例
在一個函數中定義另一個會使閉包變得更加復雜。例如:
~~~
var iBaseNum = 10;//全局變量
function addNum(iNum1, iNum2) {
function doAdd() {
return iNum1 + iNum2 + iBaseNum;
}
return doAdd();
}
document.write(addNum(10,10));
~~~
這里,函數addNum()包括函數doAdd()(閉包)。內部函數是一個閉包,因為它將獲取外部函數的參數iNum1和iNum2以及全局變量iBaseNum的值。 addNum()的最后一步調用了doAdd(),把兩個參數和全局變量相加,并返回它們的和。這里要掌握的重要概念是,doAdd()函數根本不接受參數,它使用的值是從執行環境中獲取的,因此輸出的結果為:30。
可以看到,閉包是 ECMAScript 中非常強大多用的一部分,可用于執行復雜的計算。就像使用任何高級函數一樣,使用閉包要小心,因為它們可能會變得非常復雜。
如果想要學習更加詳細的JS函數的知識,參考[ECMAScript函數]()。
- 前言
- HTML學習1:Dreamweaver8的安裝
- HTML學習2:初識HTML
- HTML學習3:常用標簽之文本標簽
- HTML學習4:常用標簽之列表標簽
- HTML學習5:常用標簽之圖像標簽
- HTML學習6:常用標簽之超鏈接標簽
- HTML學習7:常用標簽之表格標簽
- HTML學習8:常用標簽之框架標簽
- HTML學習9:常用標簽之表單標簽
- HTML學習10:表單格式化
- HTML學習11:HTTP 方法
- HTML學習12:其他常見標簽之頭標簽
- HTML學習13:其他常見標簽之體標簽
- 輕松學習JavaScript一:為什么學習JavaScript
- 輕松學習JavaScript二:JavaScript語言的基本語法要求
- 輕松學習JavaScript三:JavaScript與HTML的結合
- 輕松學習JavaScript四:JS點擊燈泡來點亮或熄滅這盞燈的網頁特效映射出JS在HTML中作用
- 輕松學習JavaScript五:JavaScript的變量和數據類型
- 輕松學習JavaScript六:JavaScript的表達式與運算符
- 輕松學習JavaScript七:JavaScript的流程控制語句
- 輕松學習JavaScript八:JavaScript函數
- 輕松學習JavaScript九:JavaScript對象和數組
- 輕松學習JavaScript十:JavaScript的Date對象制作一個簡易鐘表
- 輕松學習JavaScript十一:JavaScript基本類型(包含類型轉換)和引用類型
- 輕松學習JavaScript十二:JavaScript基于面向對象之創建對象(一)
- 輕松學習JavaScript十二:JavaScript基于面向對象之創建對象(二)
- 輕松學習JavaScript十三:JavaScript基于面向對象之繼承(包含面向對象繼承機制)
- 輕松學習JavaScript十四:JavaScript的RegExp對象(正則表達式)
- 輕松學習JavaScript十五:JavaScript之BOM簡介
- 輕松學習JavaScript十六:JavaScript的BOM學習(一)
- 輕松學習JavaScript十七:JavaScript的BOM學習(二)
- 輕松學習JavaScript二十九:JavaScript中的this詳解
- CSS基礎學習一:CSS概述
- CSS基礎學習二:如何創建 CSS
- CSS基礎學習三:CSS語法
- CSS基礎學習四:元素選擇器
- CSS基礎學習五:類選擇器
- CSS基礎學習六:id選擇器
- CSS基礎學習七:屬性選擇器
- CSS基礎學習八:派生選擇器
- CSS基礎學習九:偽類
- CSS基礎學習十:偽元素
- CSS基礎學習十一:選擇器的優先級
- CSS基礎學習十二:CSS樣式
- CSS基礎學習十三:盒子模型
- CSS基礎學習十四:盒子模型補充之display屬性設置
- CSS基礎學習十五:盒子模型補充之外邊距合并
- CSS基礎學習十六:CSS盒子模型補充之border-radius屬性
- CSS基礎學習十七:CSS布局之定位
- CSS基礎學習十八:CSS布局之浮動
- CSS基礎學習十九:CSS布局之圖文混排,圖像簽名,多圖拼接和圖片特效
- DIV+CSS實操一:經管系網頁總體模塊布局
- DIV+CSS實操二:經管系網頁添加導航欄和友情鏈接欄
- DIV+CSS實操三:經管系網頁內容模塊添加標題欄和版權信息模塊
- DIV+CSS實操四:經管系網頁內容模塊內容添加(一)
- DIV+CSS實操五:經管系網頁內容模塊內容添加(二)
- DIV+CSS實操六:經管系網頁添加導航欄下拉菜單
- DIV+CSS實操七:中文系內容模塊控制文本不換行和超出指定寬度后用省略號代替
- JS中實現字符串和數組的相互轉化