JavaScript函數(shù)

本文只是關(guān)于JavaScript函數(shù)的一些入門介紹,寫的有些寬泛和簡(jiǎn)單,目的是對(duì)JavaScript的函數(shù)有一個(gè)大概的理解谐丢。

函數(shù)定義

聲明函數(shù)

一般創(chuàng)建(聲明)一般分成四部分:

  • function關(guān)鍵字
  • 函數(shù)名稱
  • 函數(shù)的參數(shù)列表
  • 函數(shù)體:包含需要執(zhí)行的所有語(yǔ)句爽航。特別注意return語(yǔ)句,它決定了調(diào)用函數(shù)的返回值。

一般格式如下示例:

function findMax(a, b) {
    if (a >b ) {
        return a;
    } else {
        return b;
    }
}
//函數(shù)調(diào)用
var maxNumber=findMax(12, 56);

函數(shù)表達(dá)式

把上面函數(shù)聲明中的代碼去除函數(shù)名稱,就得到了一個(gè)函數(shù)表達(dá)式乾忱。一般可以把一個(gè)函數(shù)表達(dá)式賦值給一個(gè)變量,
然后我們就可以把這個(gè)變量當(dāng)成函數(shù)名稱一樣使用,進(jìn)行函數(shù)調(diào)用讥珍。把上面的函數(shù)聲明修改成表達(dá)式方式的創(chuàng)建,如下示例

var findMax = function (a, b){
    if (a >b ) {
        return a;
    } else {
        return b;
    }
}
//函數(shù)調(diào)用
var maxNumber=findMax(12, 56);

使用 new Function()創(chuàng)建函數(shù)

除了上面的函數(shù)聲明和函數(shù)表達(dá)式的方式創(chuàng)建函數(shù),我們也可以使用new Function()的方式創(chuàng)建函數(shù)。new Function()傳入的最后一個(gè)參數(shù)是函數(shù)體,
其他參數(shù)是創(chuàng)建的函數(shù)的函數(shù)參數(shù)窄瘟。上面的示例修改成new Function()方式如下:

var fundMax=new Function('a','b','if(a>b){return a;} else{return b;}');
//函數(shù)調(diào)用
var maxNumber=findMax(12, 56);

自調(diào)用函數(shù)

自調(diào)用函數(shù)一般用于一次性調(diào)用,而相比于直接把函數(shù)體中的代碼寫在全局作用域,這種方式可以避免全局作用域變量污染串述。很多JS類型就是使用這種方式編寫的。
示例代碼如下:

var maxNumber = (
    function(a, b){
        if (a >b ) {
            return a;
        } else {
            return b;
        }
    }
)(12,56);

函數(shù)聲明的提升(Hoisting)

函數(shù)聲明的提升與變量聲明的提升是一樣的概念,JS解析器會(huì)把函數(shù)的聲明提升到作用域的最上面執(zhí)行寞肖。所以可以在聲明函數(shù)之前進(jìn)行函數(shù)調(diào)用纲酗。
注意:函數(shù)表達(dá)式和new Function()的方式創(chuàng)建函數(shù)是不會(huì)被提升的。
如下示例:

//在函數(shù)聲明前進(jìn)行函數(shù)調(diào)用
var maxNumber=findMax(12, 56);
//函數(shù)聲明
function findMax(a, b) {
    if (a >b ) {
        return a;
    } else {
        return b;
    }
}

函數(shù)是一種特殊的對(duì)象

JS中除了值類型(string/number/boolean/null/undefined)的變量,其他變量都是引用類型新蟆。而所有的引用類型的變量都是繼承Object對(duì)象觅赊。
函數(shù)也是一種特殊的對(duì)象,也是繼承自O(shè)bject∏淼荆可以使用如下代碼進(jìn)行測(cè)試吮螺。

function findMax(a, b){
    if (a >b ) {
        return a;
    } else {
        return b;
    }
}
//所有的函數(shù)都是Function類型的
console.log(findMax instanceof Function); //輸出true
//而Function是繼承自O(shè)bject,所以所有的函數(shù)也是繼承自O(shè)bject。(也就是所有的函數(shù)都是Object的子類)
console.log(findMax instanceof Object);  //輸出true

函數(shù)參數(shù)

函數(shù)的顯示參數(shù)和隱式參數(shù)

在函數(shù)聲明中的參數(shù)列表的參數(shù)都稱為顯示參數(shù),也叫做形參帕翻。

在函數(shù)調(diào)用時(shí)傳入的所有的參數(shù)都稱為隱式參數(shù),也叫做實(shí)參鸠补。

如下代碼示例:

//這是函數(shù)聲明。a和b兩個(gè)參數(shù)稱之為函數(shù)的顯示參數(shù),也叫做形參嘀掸。
function findMax(a, b) {
    if (a >b ) {
        return a;
    } else {
        return b;
    }
}
//這是函數(shù)調(diào)用紫岩。傳入的12和56成為函數(shù)的隱式參數(shù),也叫做實(shí)參。
var maxNumber=findMax(12, 56);

函數(shù)參數(shù)的一些規(guī)則

JS是弱類型語(yǔ)言,所以函數(shù)參數(shù)存在如下一些規(guī)則:

  • 聲明函數(shù)的時(shí)候不需要指定形參的數(shù)據(jù)類型
  • 函數(shù)調(diào)用的時(shí)候不會(huì)對(duì)實(shí)參的數(shù)據(jù)類型和個(gè)數(shù)進(jìn)行檢測(cè)睬塌。

如果需要對(duì)函數(shù)參數(shù)的數(shù)據(jù)類型和個(gè)數(shù)進(jìn)行檢測(cè),則需要自己在函數(shù)內(nèi)部編寫代碼進(jìn)行參數(shù)類型和個(gè)數(shù)的檢測(cè)泉蝌。

函數(shù)參數(shù)的默認(rèn)值

很多語(yǔ)言都可以對(duì)函數(shù)的參數(shù)設(shè)置默認(rèn)值:當(dāng)調(diào)用函數(shù)時(shí),對(duì)應(yīng)的參數(shù)沒有傳入,則該參數(shù)的值就為設(shè)置的默認(rèn)值。
但是在ES6版本之前的JS語(yǔ)法是不支持函數(shù)參數(shù)默認(rèn)值設(shè)置的揩晴。所以我們使用如下的方式實(shí)現(xiàn)函數(shù)參數(shù)默認(rèn)值的效果:

function findMax(a, b) {
    //相當(dāng)于給參數(shù)a設(shè)置默認(rèn)值為0
    a = a || 0;
    //相當(dāng)于給參數(shù)b設(shè)置默認(rèn)值為0
    b = b || 0;
    
    if (a >b ) {
        return a;
    } else {
        return b;
    }
}

函數(shù)的arguments對(duì)象

在函數(shù)體中我們可以使用arguments對(duì)象來(lái)獲取函數(shù)調(diào)用時(shí)傳入的實(shí)參數(shù)據(jù)勋陪。這并不受形參的影響。如下代碼示例:

//沒有一個(gè)形參
function findMax(){
    //使用使用arguments.length獲取實(shí)參個(gè)數(shù),可以像數(shù)組一樣訪問實(shí)參的值
    for(var i=0, maxNumber=arguments[0]; i< arguments.length; i++){
        if(arguments[i] > maxNumber){
            maxNumber = arguments[i];
        }
    }
    return maxNumber;
}

//函數(shù)調(diào)用傳入的實(shí)參
var maxNumber=findMax(12,-1,34,544,55,0);

函數(shù)參數(shù)的值傳遞和引用傳遞

數(shù)據(jù)類型分成兩大類:值類型和引用類型硫兰。如果函數(shù)調(diào)用時(shí),實(shí)參是值類型就成為值傳遞,實(shí)參為引用類型就成為引用傳遞诅愚。如果需要深入了解其中的原理,
就需要知道值類型和引用類型變量的內(nèi)存分配機(jī)制和內(nèi)存中的知識(shí)。這里不做深入,相關(guān)知識(shí)網(wǎng)上有很多劫映。
這里通過如下示例解釋一下參數(shù)的值傳遞和引用傳遞违孝。

function double(number,numberList){
    number *= 2;
    for(var i=0; i< numberList.length; i++){
        numberList[i] *= 2;
    }
}
var num=3,
    numList=[3, 5];
double(num,numList);

//因?yàn)閚um是值類型,所以num在double(num,numList)函數(shù)執(zhí)行后值沒有改變:3
console.log(num);
//因?yàn)閚umList是引用類型,所以numList在double(num,numList)函數(shù)執(zhí)行之后值發(fā)生了改變:[6,10]
console.log(numList);

函數(shù)調(diào)用

把函數(shù)調(diào)用表達(dá)式看作一個(gè)值使用

可以把函數(shù)調(diào)用看作一個(gè)值來(lái)使用刹前,這個(gè)值是由函數(shù)的返回值決定的。如下示例代碼:

function findMax(){
    for(var i=0,maxNumber=arguments[0]; i<arguments.length; i++){
        if(maxNumber<arguments[i]){
            maxNumber=arguments[i];
        }
    }
    return arguments[i];
}
//這里我們就可以把函數(shù)調(diào)用findMax(12,45,2)看作一個(gè)整數(shù)等浊,因?yàn)樵摵瘮?shù)調(diào)用表達(dá)式返回一個(gè)整數(shù)腮郊。
var maxDouble=findMax(12,45,2) * 2;

全局函數(shù)

在全局作用域中創(chuàng)建的函數(shù)叫做全局函數(shù)。而web應(yīng)用中所有的全局變量和函數(shù)都屬于全局對(duì)象window的屬性筹燕。
所以我們可以把全局函數(shù)看作是window對(duì)象的方法轧飞。如下示例代碼:

function sum(a, b){
    return a+b;
}
var a;
//下面兩個(gè)調(diào)用是等價(jià)的
a= sum(1,3);
a=window.sum(1,3);

函數(shù)中的this關(guān)鍵字

函數(shù)中的this是一個(gè)關(guān)鍵字,this指向調(diào)用當(dāng)前函數(shù)的對(duì)象撒踪。如下示例:

function setFirstName(firstName){
    this.firstName=firstName;
}
//在全局作用域中直接調(diào)用过咬,則this指向全局對(duì)象(window)。因?yàn)樵谌终{(diào)用setFirstName()相當(dāng)于window.setFirstName()
setFirstName("james");  //等價(jià)于window.setFirstName("james");

var obj={
    firstName:"pual",
    setFirstName:setFirstName
};
//這是this指向obj對(duì)象制妄。
obj.setFirstName("james");

//把函數(shù)當(dāng)成構(gòu)造函數(shù)使用時(shí)掸绞,this指向構(gòu)造的對(duì)象。
var obj1=new setFirstName("james");

函數(shù)作為方法調(diào)用

當(dāng)函數(shù)作為對(duì)象成員的時(shí)候耕捞,我們稱該函數(shù)為對(duì)象的方法衔掸。這時(shí)我們可以通過對(duì)象來(lái)調(diào)用該方法。
如下示例:

var person={
    firstName:"james",
    lastName:"young",
    getFullName:function(){
        return this.firstName + " " + this.lastName;
    }
};
//通過對(duì)象調(diào)用該對(duì)象的方法
var fullName=person.getFullName();

構(gòu)造函數(shù)

構(gòu)造函數(shù)本身就是一個(gè)普通的函數(shù)俺抽。所以所有的函數(shù)都可以是構(gòu)造函數(shù)敞映,只需要在函數(shù)調(diào)用的前面加上new關(guān)鍵字時(shí),
我們就稱該函數(shù)為構(gòu)造函數(shù)磷斧。但是構(gòu)造函數(shù)的一般情況下主要目的是用于構(gòu)造對(duì)象振愿。
如下示例:

function Person(name,age){
    this.name=name;
    this.age=age;
    this.grow=function(){
        this.age += 1;
    }
}
//使用上面的函數(shù)構(gòu)造對(duì)象,則這個(gè)函數(shù)就稱為構(gòu)造函數(shù)了
var person=new Person("趙四",34);
//使用對(duì)象成員(屬性和方法)
console.log(person.name);
person.grow();

函數(shù)的call和apply方法

函數(shù)是對(duì)象類型的弛饭,所以函數(shù)也有屬性和方法冕末。函數(shù)有兩個(gè)常用的方式:callapply
如果存在一個(gè)函數(shù)dumpObject,即便它不是某個(gè)對(duì)象obj的方法侣颂,
也可以通過dumpObject函數(shù)的call或者apply方法實(shí)現(xiàn):對(duì)象obj對(duì)函數(shù)dumpObject的調(diào)用,
也就是函數(shù)dumpObject中的this關(guān)鍵字指向?qū)ο?code>obj档桃。
如下示例:

function dumpObject(prefix,suffix){
    var dumpString=prefix;
    for(var prop in this){
        dumpString += prop + ':' + this[prop] + '\n\r';
    }
    dumpString += suffix;
    console.log(dumpString);
}
//創(chuàng)建一個(gè)對(duì)象,該對(duì)象不存在dumpObject方法
var obj={
    name:"趙四",
    age:78,
    score:70
};
//可以使用函數(shù)的call或者apply方法實(shí)現(xiàn):obj像調(diào)用自己方法一樣的效果調(diào)用dumpObject函數(shù)
var prefix='***start***\n\r',
    suffix='***start***\n\r';
dumpObject.call(obj,prefix,suffix);
//從函數(shù)調(diào)用中可以看出横蜒,apply與call的唯一不用是:apply方法通過數(shù)組的形式胳蛮,把函數(shù)dumpObject的參數(shù)組織成apply的一個(gè)參數(shù)。
dumpObject.apply(obj,[prefix,suffix]);

閉包

什么是閉包

閉包的概念其實(shí)很簡(jiǎn)單,一句話就可以表達(dá)丛晌。

閉包是可以訪問上一層函數(shù)作用域里變量的函數(shù),即便上一層函數(shù)已經(jīng)關(guān)閉个盆。

但是需要理解這句話還是需要些功夫的哗讥。首先提取一下這句話,得到三個(gè)關(guān)鍵點(diǎn):

  • 閉包是函數(shù)
  • 閉包可以訪問上一層函數(shù)作用域變量:閉包是內(nèi)嵌函數(shù),而且可以訪問了上一層函數(shù)的局部變量。
  • 即便是上一層函數(shù)已經(jīng)關(guān)閉:需要把閉包使用return語(yǔ)句返回躏鱼。
    還需要清楚的一個(gè)概念是:JavaScript中所有函數(shù)都能訪問它們上層作用域中的變量蜕窿。
    閉包實(shí)現(xiàn)一個(gè)計(jì)數(shù)器的實(shí)例代碼:
//使用一個(gè)自調(diào)用函數(shù),得到了一個(gè)閉包
var counter=(
    function(){
        var count = 0;
        //返回的函數(shù)就是閉包,訪問了上一層函數(shù)的count局部變量
        return function(){
            count += 1;
        }
    }
)();

為什么需要閉包

上面介紹了什么是閉包谋逻。但是我們?yōu)槭裁葱枰]包呢?需要明白這個(gè)問題前需要了解局部變量全局變量的局限性,已經(jīng)閉包的特性呆馁。
局部變量的特點(diǎn)是:函數(shù)執(zhí)行完就被銷毀,所以無(wú)法實(shí)現(xiàn)變量的累積(如計(jì)數(shù)器的功能)。
全局變量的特點(diǎn)是:在全局都可以訪問,只有在頁(yè)面關(guān)閉后才銷毀毁兆≌懵耍可以實(shí)現(xiàn)指定的計(jì)數(shù)器功能。問題在于:全局變量是所有地方都可以修改,
而且盡量少使用全局變量,避免全局變量污染气堕。

針對(duì)全局變量局部變量在這種場(chǎng)景下存在的問題,閉包的相關(guān)特性正好能夠解決這個(gè)問題纺腊。因?yàn)殚]包可以使用上一層函數(shù)的局部變量,
這樣避免了全局變量的污染。而且因?yàn)殚]包被上一層函數(shù)返回,并且被外部引用,所以閉包引用了的上層函數(shù)的變量在上層函數(shù)結(jié)束后依然不會(huì)被銷毀茎芭。
這樣又避免了普通局部變量在函數(shù)執(zhí)行完就被銷毀,無(wú)法累積的問題揖膜。

所以這就是閉包的特性。也是閉包被使用的場(chǎng)景梅桩。

在編寫javascript代碼時(shí)壹粟,我們也要警惕閉包帶來(lái)的問題:引用的局部變量遲遲不能釋放,容易導(dǎo)致內(nèi)存的泄露。

這里只是簡(jiǎn)單的介紹了一下閉包,以后有機(jī)會(huì)可以專門寫一篇關(guān)于閉包的文章宿百。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末趁仙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子垦页,更是在濱河造成了極大的恐慌雀费,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件外臂,死亡現(xiàn)場(chǎng)離奇詭異坐儿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宋光,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門貌矿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人罪佳,你說我怎么就攤上這事逛漫。” “怎么了赘艳?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵酌毡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我蕾管,道長(zhǎng)枷踏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任掰曾,我火速辦了婚禮旭蠕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己掏熬,他們只是感情好佑稠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旗芬,像睡著了一般舌胶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疮丛,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天幔嫂,我揣著相機(jī)與錄音,去河邊找鬼这刷。 笑死婉烟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的暇屋。 我是一名探鬼主播似袁,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼咐刨!你這毒婦竟也來(lái)了昙衅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤定鸟,失蹤者是張志新(化名)和其女友劉穎而涉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體联予,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啼县,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沸久。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片季眷。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卷胯,靈堂內(nèi)的尸體忽然破棺而出子刮,到底是詐尸還是另有隱情,我是刑警寧澤窑睁,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布挺峡,位于F島的核電站,受9級(jí)特大地震影響担钮,放射性物質(zhì)發(fā)生泄漏橱赠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一箫津、第九天 我趴在偏房一處隱蔽的房頂上張望病线。 院中可真熱鬧吓著,春花似錦鲤嫡、人聲如沸送挑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惕耕。三九已至,卻和暖如春诫肠,著一層夾襖步出監(jiān)牢的瞬間司澎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工栋豫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挤安,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓丧鸯,卻偏偏與公主長(zhǎng)得像蛤铜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丛肢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)函數(shù)定義與調(diào)用變量作用域全局變量方法高階函數(shù)閉包箭頭函數(shù)$generator$ 函數(shù) 函數(shù)定義與調(diào)用 定義函數(shù)...
    染微言閱讀 583評(píng)論 0 5
  • JavaScript筆記(三) 函數(shù) 理解函數(shù) Javascript函數(shù)的參數(shù)與大多數(shù)其他語(yǔ)言中的函數(shù)的參數(shù)不同蜂怎。...
    運(yùn)維開發(fā)筆記閱讀 276評(píng)論 0 0
  • 本文是大神廖雪峰的JavaScript教程學(xué)習(xí)筆記穆刻。并不是教程,如有需要杠步,請(qǐng)前往廖雪峰大神大博客. 一氢伟、函數(shù)定義和...
    0o凍僵的企鵝o0閱讀 486評(píng)論 1 3
  • 86.復(fù)合 Cases 共享相同代碼塊的多個(gè)switch 分支 分支可以合并, 寫在分支后用逗號(hào)分開。如果任何模式...
    無(wú)灃閱讀 1,364評(píng)論 1 5
  • 文/孤鳥差魚 過早的凌遲 毀壞了 你給我的無(wú)期徒刑
    孤鳥差魚閱讀 177評(píng)論 2 5