JavaScript 中函數(shù)的應(yīng)用十分的廣泛圈匆,如果你仔細(xì)研究過(guò)JQuery等庫(kù)的話,你會(huì)發(fā)現(xiàn)
基本JQuery所提供的庫(kù)格嗅,都是可以接收一個(gè)函數(shù)作為傳入?yún)?shù)番挺,達(dá)到更靈活的目的。
0x00 函數(shù)的主要用途
在JS中屯掖,函數(shù)的用途無(wú)外乎以下集中:
- 作為函數(shù)調(diào)用
- 作為方法調(diào)用
- 作為構(gòu)造器調(diào)用
- 指定上下文調(diào)用
作為函數(shù)和方法調(diào)用的玄柏,是比較熟悉的。如果直接定義的情況下贴铜,我們認(rèn)為是做為函數(shù)調(diào)用粪摘,而將一個(gè)函數(shù)具體賦給了一個(gè)對(duì)象后瀑晒,我們稱之為做為方法調(diào)用。
但是徘意,這二者之間的區(qū)別是可以被模糊掉的苔悦。例如,我們?cè)谌汁h(huán)境下聲明一個(gè)函數(shù)映砖,其實(shí)是可以看作是在window
對(duì)象上面定義了一個(gè)方法。因?yàn)閺纳舷挛牡慕嵌葋?lái)講邑退,函數(shù)的的上下文
是不可或缺的。因此蜈七,一個(gè)函數(shù)調(diào)用,其實(shí)就是一個(gè)賦予它上下文執(zhí)行的過(guò)程飒硅。
作為構(gòu)造器調(diào)用的過(guò)程作谚,其實(shí)就是用一個(gè)函數(shù)聲稱一個(gè)對(duì)象。這個(gè)函數(shù)的額作用就是返回一個(gè)對(duì)象雀监。如下面的一個(gè)構(gòu)造器:
function Person() {
this.age = 22;
this.say = function() {
return "hello";
};
}
var p1 = new Person();
這里特別的就是 new 關(guān)鍵字会前,這關(guān)鍵字其實(shí)就是創(chuàng)建一個(gè)空對(duì)象匾竿,將這個(gè)空對(duì)象作為函數(shù)的上下文傳遞給函數(shù)岭妖,如果沒(méi)有顯示的返回值,則將此對(duì)象返回苔巨。這點(diǎn)废离,有過(guò)其他面向?qū)?br> 象編程經(jīng)驗(yàn)的蜻韭,自然不言自明。
指定上下文的調(diào)用的過(guò)程非洲,就是用到了函數(shù)的兩個(gè)重要方法俯画,apply()
和call()
這兩個(gè)方法的作用是一樣的,都是給函數(shù)指定一個(gè)上下文艰垂,然后調(diào)用它。這種機(jī)制娩怎,在很多支持事件回
調(diào)的函數(shù)中截亦,都可以看到柬讨。
0x01 匿名函數(shù)
匿名函數(shù) 顧名思義,就是沒(méi)有名字的函數(shù)却桶。我們來(lái)看兩種函數(shù)的聲明定義:
function foo1() {
return "123";
}
var foo2 = function() {
return "456";
};
foo1();
foo2();
這兩種看起來(lái)沒(méi)有什么太大的差異肾扰,但是如果你直接通過(guò)函數(shù)名調(diào)用蛋逾,你會(huì)發(fā)現(xiàn)不一樣的結(jié)果:
>foo1
< function foo1(){...};
>foo2
< function(){...};
第二個(gè)函數(shù)的用法,就稱之為匿名函數(shù)偷拔。他沒(méi)有直接給于一個(gè)名字莲绰,就是沒(méi)有直接給定上下文姑丑。而是通過(guò)賦值給某個(gè)變量,對(duì)象的屬性震肮,來(lái)指定一個(gè)匿名函數(shù)上下文。而有名函數(shù)的聲明過(guò)
程鲫尊,就是在上下文中綁定了一個(gè)這個(gè)函數(shù)名的屬性沦偎。上例子中,我們可以通
過(guò)window
調(diào)用也是一樣的:
window.foo1
0x02 即時(shí)函數(shù)
有經(jīng)驗(yàn)的老司機(jī)同志搔驼,一定見(jiàn)過(guò)這樣的函數(shù)調(diào)用方式:
(function(){})();
而這樣的一行代碼匙奴,就可以將一個(gè)函數(shù)執(zhí)行妄荔。這里特別注意的是兩個(gè)括號(hào),可以精剪為:
(...)();
第一個(gè)括號(hào)的哗伯,接收的是一個(gè)函數(shù)焊刹,可以是一個(gè)匿名函數(shù)恳蹲,也可以是一個(gè)已經(jīng)聲明的函數(shù)的名字或者調(diào)用。第二個(gè)括號(hào)里面標(biāo)識(shí)的是注入?yún)?shù)贺奠,即我們?cè)诘谝粋€(gè)括號(hào)中的函數(shù)的參數(shù)错忱,可以
通過(guò)第二個(gè)括號(hào)來(lái)注入以清。如:
(function(a,b) {
return a+b;
})(1,2);
// out 3
這段代碼的作用其實(shí)就是如下的四個(gè)步驟:
- 創(chuàng)建一個(gè)函數(shù)實(shí)例
- 執(zhí)行該函數(shù)
- 銷毀該函數(shù)(應(yīng)為沒(méi)有引用這個(gè)函數(shù)的引用了)
題,完成之后眉孩,便可以銷毀勺像,避免了全局環(huán)境被污染的問(wèn)題。
看下面這段代碼:
(function(app) {
app.AppComponent =
ng.core.Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
.Class({
constructor: function() {}
});
})(window.app || (window.app = {}));
靈活的控制全局環(huán)境的生成吟宦。
0x03 遞歸函數(shù)
遞歸是需要結(jié)果很多重復(fù)操作的選擇殃姓,性能方面的我們暫且不說(shuō)蜗侈,但是從另一個(gè)角度來(lái)說(shuō)
睡蟋,至少代碼
夠簡(jiǎn)練。但是该面,如果沒(méi)遇到一種情況:
obj.foo = function(){};
我們要在這個(gè)函數(shù)的內(nèi)部隔缀,進(jìn)行遞歸調(diào)用傍菇,誠(chéng)然我們直接通過(guò)在方法的內(nèi)部調(diào)用:
obj.foo = function(){
obj.foo();
};
這樣的方式,在這個(gè)函數(shù)的上下文沒(méi)有被改動(dòng)的情況下丢习,是可行的咐低。當(dāng)然我們進(jìn)一步,采
用this
:
obj.foo = function(){
this.foo();
};
這樣的情況绰更,要求每個(gè)調(diào)用的這個(gè)函數(shù)的方法屬性都叫做foo
锡宋,萬(wàn)一名字變了执俩,又是個(gè)
坑了。那么役首,
其實(shí)JavaScript支持一種內(nèi)連函數(shù)的聲明方式显拜,如下:
obj.foo = function a(){
a();
};
給了函數(shù)一個(gè)名字远荠,就不再是匿名函數(shù)了譬淳,即時(shí)是上下文和調(diào)用名字變了,依然可以安心的遞歸下去邻梆。
注意:值得注意的是绎秒,函數(shù)的
arguments
對(duì)象中见芹,有一個(gè)叫callee
的屬性,這個(gè)
屬性就是用來(lái)指代函數(shù)本身的辆童,不過(guò)這個(gè)函數(shù)是有名還是匿名把鉴。但是這個(gè)屬性有被取消的
趨勢(shì),并且在嚴(yán)格模式下已經(jīng)是不可用的了场晶。
0x04 函數(shù)即對(duì)象怠缸?
JavaScript中,函數(shù)是作為第一型對(duì)象存在的扳炬。這既是一種函數(shù)式編程的方式恨樟,又是一
種面向?qū)ο蟮姆绞骄尉悖院芏嘣讨贾髁x者,對(duì)此十分反感。但是我認(rèn)為衬吆,真是結(jié)合了
這兩者形式逊抡,才是功能強(qiáng)大的原因零酪。
JavaScript中,既有代表對(duì)象的原型對(duì)象Object
又有代表函數(shù)的Function
原型對(duì)象。函數(shù)既是對(duì)象潜秋,
或者對(duì)象既是函數(shù)峻呛,這只不過(guò)是你從不同的角度來(lái)看待這件事情罷了。
0x05 總結(jié)
JavaScript一直被處在一種被忽視的地位寨躁,因?yàn)楦鞣N庫(kù)的存在牙勘,很多人執(zhí)著于庫(kù),是用JQuery
還是TypeScript
放钦,
是用AngularJS
還是React
操禀?其實(shí)横腿,我覺(jué)得這些都可以,一個(gè)庫(kù)的存在揪惦,之所以有很多人用搀别,你說(shuō)有很致命的bug,
不能說(shuō)不可能蒂培,只是可能性很小。而很多人卻忽視了JavaScript本身的問(wèn)題翎冲。包括抗悍,google也是,angularJS2.0的版本缴渊,
更加偏向于TypeScript去了鱼炒。當(dāng)然昔瞧,JavaScript有許多被人詬病的問(wèn)題。但是自晰,它畢竟是現(xiàn)在最重要的前端語(yǔ)言酬荞,(額...
node派請(qǐng)不要出來(lái)打臉)袜蚕,了解其被背后的機(jī)制,是作為一個(gè)程序員所必要的牲剃,如果你要使用到它的話凿傅。
JavaScript我認(rèn)為最重要的幾個(gè)特性聪舒,就是:
- 函數(shù)
- 對(duì)象
- 正則表達(dá)式
- 定時(shí)器
這四者之間,相互交叉那是當(dāng)然的滔迈,而我認(rèn)為,這四者之中敬惦,最基礎(chǔ)的是函數(shù)谈山。正則雖然有些不同,當(dāng)在JavaScript畴椰,中正則
是屬于特殊對(duì)象的范疇斜脂。在應(yīng)用過(guò)程中秽褒,使用到函數(shù)的那是必不可少的威兜。所以...
函數(shù)為基椒舵。
我的blog原址: