詳解JavaScript函數(shù)
函數(shù)是一組可以隨時隨地運行的語句,函數(shù)作為ECMAScript的核心是很重要的。函數(shù)是由事件驅(qū)動的或者當它被調(diào)用時執(zhí)行的可重復(fù)使用的代碼塊。也就是函數(shù)是定義一次但卻可以調(diào)用或執(zhí)行任意多次的一段JavaScript代碼。函數(shù)有時會有參數(shù),即函數(shù)被調(diào)用時指定了值的局部變量。函數(shù)常常使用這些參數(shù)來計算一個返回值,這個值也成為函數(shù)調(diào)用表達式的值。
一、函數(shù)聲明
函數(shù)對于任何語言來說都是一個核心的概念。通過函數(shù)可以封裝任意多條語句,而且可以在任何地方,任何時候調(diào)用執(zhí)行。JS中的函數(shù)使用function關(guān)鍵字來聲明,后跟一組參數(shù)以及函數(shù)體。
函數(shù)的基本語法是這樣的:
<span style="font-size:18px;">function functionName(arg0, arg1, ... argN) { statements }</span>
ECMAScript規(guī)定的函數(shù)聲明方式有三種:
(1)普通函數(shù)聲明
<span style="font-size:18px;">function box(num1,num2){ return num1+num2; }</span>
(2)使用變量初始化什聲明函數(shù)
<span style="font-size:18px;">var box=function(num1,num2){ return num1+num2; }</span>
(3)使用Function構(gòu)造函數(shù)聲明
二、函數(shù)的類型及函數(shù)的調(diào)用
ECMAScript語法規(guī)定了
(1)無參數(shù)的函數(shù):函數(shù)的聲明的時候沒有參數(shù),調(diào)用函數(shù)的時候直接使用即可。
function box(){ document.write("我是中國人!"); } box();//函數(shù)調(diào)用
運行的結(jié)果為:我是中國人!
(2)帶參數(shù)的函數(shù):函數(shù)的聲明的時候同時定義了參數(shù)變量,參數(shù)可以是多個。
function box(name,age) { document.write("你的姓名是:"+name+"你的年齡是:"+age); } box("張三","24");//函數(shù)調(diào)用
運行的結(jié)果為:你的姓名是:張三
你的年齡是:24
(3)帶有返回值的函數(shù)
帶參數(shù)和無參數(shù)的函數(shù),都沒有定義返回值,而是調(diào)用后直接執(zhí)行的,實際上,任何函數(shù)都可以通過return語句跟后面的要返回的值來實現(xiàn)返回值
1)、無參數(shù)的函數(shù)
function box(){ return "我是中國人!"; } document.write(box());
同上面的輸出結(jié)果:我是中國人!
2)、帶參數(shù)的函數(shù)
function box(name,age){ return "你的姓名是:"+name+"<br/>"+"你的年齡是:"+age; } document.write(box("張三","24"));//函數(shù)調(diào)用 document.write("<hr/>"); var demo=box("李四","23");//也可以重新賦值新的函數(shù) document.write(demo);
運行的結(jié)果為:
(4)作為值的函數(shù)(比較特殊)
首先我們來看一個函數(shù)作為常規(guī)的變量的例子:
function box(sum,num){ return sum+num;//這里傳遞的是函數(shù)的返回值和普通的變量一樣 } function sum(num){ return num+10; } var result=box(sum(10),10); document.write("result="+result);
頁面的輸出結(jié)果為:result=30
下面則傳遞的是函數(shù),仔細和上面的區(qū)分:
function box(sum,num){ return sum(num);//這里傳遞的是函數(shù) } function sum(num){ return num+10; } var result=box(sum,10); document.write("result="+result);
頁面的輸出結(jié)果為:result=20
三、函數(shù)的內(nèi)部屬性
在函數(shù)內(nèi)部,有兩個特殊的對象:arguments對象和this對象。arguments對象是類數(shù)組對象,包含著傳入函數(shù)中的所有參數(shù),主要用途是保存函數(shù)參數(shù),主要的屬性有l(wèi)ength,這個屬性是動態(tài)的判斷函數(shù)有多少個參數(shù)。但這個對象還有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數(shù)。
(1)arguments對象的length屬性
JS函數(shù)不介意傳遞進來多少參數(shù),也不會因為參數(shù)不統(tǒng)一而錯誤。實際上,函數(shù)體內(nèi)可以通過arguments對象來
接收傳遞進來的參數(shù)。
我們先來看一個我們在函數(shù)傳遞參數(shù)遇到的問題:函數(shù)聲明時并不知道要定義多少個參數(shù),在調(diào)用函數(shù)卻出現(xiàn)多
出的或不足的問題。
function box(){ return arguments[0]+"|"+arguments[1]; } document.write(box(1,2,3,4,5,6));
輸出的結(jié)果為:1|2。因此輸出的顯然與我們想要做的不符,那么怎么解決呢?
有了arguments對象的length屬性我們就能可以得到參數(shù)的數(shù)量,避免上面的錯誤出現(xiàn)。
function box(){ return arguments.length; } document.write(box(1,2,3,4,5,6));
輸出:6
我們還可以利用length屬性來智能的判斷有多少參數(shù),然后把參數(shù)進行合理的應(yīng)用,比如,實現(xiàn)一個加法運算,將所有傳進來的數(shù)字累加,而數(shù)字的個數(shù)又不確定。
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;//返回累加結(jié)果 } 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
對于階乘函數(shù)一般要用到遞歸算法,所以函數(shù)內(nèi)部一定對調(diào)用自身,如果函數(shù)名不改變是沒有問題的,但一旦改變函數(shù)名,內(nèi)部的自身調(diào)用需要逐一修改。為了解決這個問題,可以使用arguments.callee來代替。
function box(num){ if(num<=1) { return 1; } else { return num*arguments.callee(num-1)//遞歸 } } document.write(box(4));
輸出:24
(3)this對象
函數(shù)內(nèi)部另一個特殊的對象時this,其行為與Java和C#中的this大致相似,換句話說,this引用的是函數(shù)據(jù)以行操作的對象,或者說函數(shù)調(diào)用語句所處的那個作用域。當在全局作用域中調(diào)用函數(shù)時,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);//全局的
運行的結(jié)果為:
四、函數(shù)屬性和方法
(1)JavaScript中的函數(shù)是對象,因此函數(shù)也有屬性和方法。每個函數(shù)都包含兩個屬性:length和prototype。其中,length屬性表示函數(shù)希望接受的命名參數(shù)的個數(shù)。
function box(num1,num2){ return num1+num2; } document.write(box.length);
輸出的結(jié)果;2
對于prototype屬性,它是保存所有實例方法的真正所在,也就是原型。這個屬性我們先不做過多的介紹。prototype屬性下有兩個方法:apply()和call(),每個函數(shù)都包含這兩個非繼承而來的方法。這兩個方法的用途都在特定的作用域中調(diào)用函數(shù),實際上等于設(shè)置函數(shù)體內(nèi)this對象的值。
function box(num1,num2){ return num1+num2; } function sayBox(num1,num2){ return box.apply(this,[num1,num2]);//this表示作用域,這里是window,[]表示box所需的參數(shù) } function sayBox2(num1,num2){ return box.apply(this,arguments);//arguments對象表示box所需的參數(shù) } document.write(sayBox(10,10)+"<br/>"); document.write(sayBox2(10,10));
輸出的結(jié)果為:20
20
(2)call()方法和apply()方法延伸
call()方法和apply()方法相同,它們的區(qū)別僅僅在于接收參數(shù)的方式不同。對于call()方法而言,第一個參數(shù)作用域,沒有變化,變化的只是其余參數(shù)都是直接傳遞給函數(shù)的。
function box(num1,num2){ return num1+num2; } function callBox(num1,num2){ return box.call(this,num1,num2);//區(qū)別apply()方法 } document.write(callBox(10,10));
輸出的結(jié)果為:20
call()方法和apply()方法真正的作用是擴展函數(shù)賴以運行的作用域
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下,對象冒充
輸出的結(jié)果為:
使用call()方法或者apply()方法來擴充作用域的最大好處就是對象不需要與方法發(fā)生任何耦合關(guān)系。也就是說,box對象和sayColor()方法之間不會有多余的關(guān)聯(lián)操作,比如;box.sayColor=sayColor;
五、ECMAScript閉包
ECMAScrip最易讓人誤解的一點是,它支持閉包。閉包,指的是詞法表示包括不被計算的變量的函數(shù),就是說,函數(shù)可以使用函數(shù)之外定義的變量。
其實我在前面的博文已經(jīng)使用到了閉包,比如在輕松學(xué)習(xí)JavaScript七:JavaScript的流程控制語句中使用的變量time就是全局變量,函數(shù)myFunction()使用這個全局變量,并不是函數(shù)本身定義的。還是看一下那個實例吧:
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中使用全局變量是一個簡單的閉包實例。請思考下面這段代碼輸出的結(jié)果是什么:
var sMessage = "hello world"; function sayHelloWorld() { document.write(sMessage); } sayHelloWorld();
在上面這段代碼中,腳本被載入內(nèi)存后,并沒有為函數(shù)sayHelloWorld()計算變量sMessage的值。該數(shù)捕 sMessage的值只是為了以后的使用,也就是說,解釋程序知道在調(diào)用該函數(shù)時要檢查sMessage的值。sMessage將在函數(shù)調(diào)用sayHelloWorld()是在(最后一行)被賦值,顯示消息"hello world"。
(2)復(fù)雜的閉包實例
在一個函數(shù)中定義另一個會使閉包變得更加復(fù)雜。例如:
var iBaseNum = 10;//全局變量 function addNum(iNum1, iNum2) { function doAdd() { return iNum1 + iNum2 + iBaseNum; } return doAdd(); } document.write(addNum(10,10));
這里,函數(shù)addNum()包括函數(shù)doAdd()(閉包)。內(nèi)部函數(shù)是一個閉包,因為它將獲取外部函數(shù)的參iNum1和iNum2以及全局變量iBaseNum的值。 addNum()的最后一步調(diào)用了doAdd(),把兩個參數(shù)和全局變量相加,并返回它們的和。這里要掌握的重要概念是,doAdd()函數(shù)根本不接受參數(shù),它使用的值是從執(zhí)行環(huán)境中獲取的,因此輸出的結(jié)果為:30。
可以看到,閉包是 ECMAScript 中非常強大多用的一部分,可用于執(zhí)行復(fù)雜的計算。就像使用任何高級函數(shù)一樣,使用閉包要小心,因為它們可能會變得非常復(fù)雜。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
相關(guān)文章
JSON格式的時間/Date(2367828670431)/格式轉(zhuǎn)為正常的年-月-日 格式的代碼
這篇文章主要介紹了JSON格式的時間/Date(2367828670431)/格式轉(zhuǎn)為正常的年-月-日 格式的代碼的相關(guān)資料,需要的朋友可以參考下2016-07-07Javascript 正則表達式校驗數(shù)字的簡單實例
下面小編就為大家?guī)硪黄狫avascript 正則表達式校驗數(shù)字的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11javascript實現(xiàn)根據(jù)iphone屏幕方向調(diào)用不同樣式表的方法
這篇文章主要介紹了javascript實現(xiàn)根據(jù)iphone屏幕方向調(diào)用不同樣式表的方法,涉及javascript針對樣式表動態(tài)操作的相關(guān)技巧,非常具有實用價值,需要的朋友可以參考下2015-07-07詳解微信小程序與內(nèi)嵌網(wǎng)頁交互實現(xiàn)支付功能
這篇文章主要介紹了詳解微信小程序與內(nèi)嵌網(wǎng)頁交互實現(xiàn)支付功能,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10用Javascript實現(xiàn)錨點(Anchor)間平滑跳轉(zhuǎn)
本文介紹的方法,實現(xiàn)了錨點(Anchor)間平滑跳轉(zhuǎn),效果非常不錯。2009-09-09