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

本文是作者在重讀 javascript 權(quán)威指南函數(shù)調(diào)用部分的時(shí)候的一個(gè)筆記, 算下來(lái)大概一半是書上的話, 一半是自己的理解再配上一些例子來(lái)加深印象, 分享給大家。

正文從這里開始艇挨。

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

構(gòu)成函數(shù)主體的 js 代碼在定義的時(shí)候是不會(huì)執(zhí)行的, 只有在調(diào)用該函數(shù)的時(shí)候它們才會(huì)執(zhí)行台谍。

一共有四種方式來(lái)調(diào)用 js 函數(shù)

  • 作為函數(shù)
  • 作為方法
  • 作為構(gòu)造函數(shù)
  • 通過(guò)它們的 callapply 來(lái)進(jìn)行間接調(diào)用

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

使用調(diào)用表達(dá)式可以進(jìn)行普通的函數(shù)調(diào)用也可以進(jìn)行方法調(diào)用姑裂。

對(duì)于普通的函數(shù)調(diào)用, 函數(shù)的返回值就是調(diào)用表達(dá)式的值港粱。如果該函數(shù)返回是因?yàn)榻忉屍鬟_(dá)到了結(jié)尾, 返回值就是 undefined富俄。 如果函數(shù)返回是因?yàn)榻忉屍鲌?zhí)行到一條 return 語(yǔ)句, 則返回至就是 return 會(huì)后的表達(dá)式的值, 如果 return 語(yǔ)句沒(méi)有值, 則返回 undefined眼刃。

方法調(diào)用

一個(gè)方法無(wú)非就是個(gè)保存在一個(gè)對(duì)象的屬性里的 js 函數(shù)。 如果有一個(gè)函數(shù) func 和一個(gè)對(duì)象 obj, 我們就可以為 obj 定義一個(gè)名為 method 的方法 :

obj.method = func;

調(diào)用的時(shí)候就類似這樣 :

obj.method();

在方法調(diào)用中, 函數(shù)表達(dá)是本身其實(shí)就是一個(gè)屬性訪問(wèn)表達(dá)式, 只不過(guò)這個(gè)屬性訪問(wèn)表達(dá)式最終取到的是函數(shù)的引用而非是一個(gè)具體的值脓诡。

對(duì)方法調(diào)用的參數(shù)和返回值的處理, 和上面描述的普通函數(shù)調(diào)用完全一致无午。

方法調(diào)用和函數(shù)調(diào)用有一個(gè)重要的區(qū)別, 就是調(diào)用上下文。在剛剛的 obj.method() 里面, 函數(shù)的 context 會(huì)變?yōu)?obj, 所以在函數(shù)內(nèi)部可以通過(guò) this 來(lái)取到 obj 的引用祝谚。

方法和 this 關(guān)鍵字是面向?qū)ο缶幊谭独暮诵南艹佟H魏魏瘮?shù)只要作為方法調(diào)用實(shí)際上都會(huì)傳入一個(gè)隱式的實(shí)參, 這個(gè)實(shí)參實(shí)際上是一個(gè)對(duì)象, 方法調(diào)用的母體就是這個(gè)對(duì)象。

需要注意的就是, this 是一個(gè)關(guān)鍵字, 不是變量也不是屬性名, 而且 js 的語(yǔ)法也不允許給 this 賦值, 但是可以預(yù)存 this, 比如我們?cè)诤瘮?shù)內(nèi)部經(jīng)常會(huì)這樣 :

function Promise (func) {
  var resolve = function (val) {
    this.resolve(val);
  };
  var reject = function (val) {
    this.reject(val);
  };
}

Promise.prototype.resolve = function () {};
Promise.prototype.reject = function () {};

接下來(lái)我們使用 var pms = new Promise(func) 來(lái)搞一個(gè)實(shí)例, 會(huì)驚奇的發(fā)現(xiàn)報(bào)錯(cuò)了.. 因?yàn)榇藭r(shí)的 this 會(huì)指向全局變量, 而全局變量上面是沒(méi)有 resolvereject 方法的, 我們的本意是想要通過(guò) this 來(lái)拿到實(shí)例 pms 的引用, 進(jìn)而從 pms 上去找到 Promise.prototype.resolve, 這個(gè)時(shí)候我們就需要把 this 的值預(yù)存一下... 就類似這種 :

function Promise (func) {
  var me = this;
  var resolve = function (val) {
    me.resolve(val);
  };
  var reject = function (val) {
    me.reject(val);
  };
}

Promise.prototype.resolve = function () {};
Promise.prototype.reject = function () {};

這樣就可以保證在實(shí)例化的時(shí)候, resolve 函數(shù)中的那個(gè) me 指向了實(shí)例, 至于這個(gè) Promise 的實(shí)現(xiàn), 具體參考了這里 https://github.com/hanan198501/promise, 當(dāng)然這不是本文要說(shuō)的, 只是意在講預(yù)存 this 的重要性

方法鏈

其實(shí)這里就涉及到原來(lái)有看過(guò)源碼的 jQuery 的鏈?zhǔn)秸{(diào)用的核心了

當(dāng)方法不需要返回值的時(shí)候, 最好直接返回 this, 如果在設(shè)計(jì) API 的時(shí)候一直采用這個(gè)方式, 就可以構(gòu)成一種鏈?zhǔn)秸{(diào)用交惯。

構(gòu)造函數(shù)調(diào)用

如果函數(shù)或者方法調(diào)用之前帶有關(guān)鍵字 new, 它就構(gòu)成了構(gòu)造函數(shù)調(diào)用次泽。這里其實(shí)說(shuō)明一件事情就說(shuō)明了整個(gè)過(guò)程了。

...所以下面就說(shuō)一下 var person = new Person() 到底發(fā)生了什么...

  • 創(chuàng)建一個(gè)新的空對(duì)象
  • 完成內(nèi)部 [[prototype]] 的指向綁定
  • Person 內(nèi)部的 this 全部指向新生成的對(duì)象
  • 最后檢測(cè) Person 內(nèi)部有沒(méi)有 return 一個(gè)對(duì)象, 如果 return的是一個(gè)對(duì)象, 則調(diào)用表達(dá)式的值就是這個(gè)對(duì)象, 沒(méi)有return或者return` 的是一個(gè)原始值的話, 則調(diào)用表達(dá)式的結(jié)果就是這個(gè)新生成的對(duì)象

這里會(huì)對(duì)第二條和第三條特殊的講一下 :

首先是第二條 : 完成內(nèi)部 [[prototype]] 的綁定

其實(shí)我們打開 chrome 控制臺(tái), 敲下 {} 按回車, 點(diǎn)開生成的那個(gè)東西, 會(huì)有一個(gè) __proto__ 的東西, 這個(gè)東西就是內(nèi)部 [[prototype]] 在瀏覽器里的實(shí)現(xiàn), 在 es6 里雖然沒(méi)有寫入正文, 但也寫入了附錄, 所以可以認(rèn)為是新的標(biāo)準(zhǔn), 在所有瀏覽器(包括 IE11) 也都部署了這個(gè)屬性(__proto__ 的描述來(lái)自于阮一峰 ECMAScript 6 入門, 傳送門 :
http://es6.ruanyifeng.com/#docs/object#proto屬性席爽,Object-setPrototypeOf意荤,Object-getPrototypeOf)。

而第二條就是做了這一個(gè)指向, 會(huì)把實(shí)例 person 內(nèi)部的 [[prototype]] (我還是更喜歡叫 __proto__ 來(lái)著...) 來(lái)指向 Person.prototype, 其實(shí)也就是這條句子所表明的那樣 :

person.__proto__ === person.constructor.prototype;

當(dāng)然明眼人有看的出來(lái)... 其實(shí) person.constructor 就是 Person, 當(dāng)然 constructor 不是這里要講的了, 只是用到了....

接下來(lái)是第三條 : 把 Person 內(nèi)部的 this 全部指向新生成的對(duì)象

這里的意思其實(shí)是, 比如 Person 內(nèi)部會(huì)有很多東西 :

function Person () {
  this.name = 'anning';
  this.age = 22;
}

在調(diào)用 var person = new Person() 的時(shí)候, 在 Person 內(nèi)部的 this 指向了新生成的對(duì)象, 也就是執(zhí)行了 :

person.name = 'anning';
person.age = 22;

這一點(diǎn)在很多地方其實(shí)都有使用, 比如 jQuery 中對(duì) jQuery.fn.init 構(gòu)造函數(shù)的實(shí)現(xiàn), 就是在 init 函數(shù)里面大量使用了 this, 在 this 上掛非繼承屬性, 最后在生成 jQuery.fn.init 的實(shí)例的時(shí)候, 使實(shí)例的非繼承屬性, 如 context 屬性, 整型屬性 [0] 等掛在了每個(gè)實(shí)例上只锻。

間接調(diào)用

間接調(diào)用中其實(shí)就只有兩個(gè)方法, callapply玖像。

兩個(gè)方法都允許顯式的指定 this 的取值, 也就是說(shuō), 所有的函數(shù)都可以作為任何對(duì)象的方法阿萊調(diào)用, 哪怕這個(gè)函數(shù)不是那個(gè)對(duì)象的方法。

我們?cè)诳吹揭恍?kù)的 this 非常強(qiáng)大的時(shí)候, 可能就是在實(shí)現(xiàn)的時(shí)候, 用 callapply 強(qiáng)行指定的...

原文地址 : http://www.amnhh.xyz/2017/02/07/%E6%B5%85%E8%B0%88%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末齐饮,一起剝皮案震驚了整個(gè)濱河市捐寥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祖驱,老刑警劉巖握恳,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異羹膳,居然都是意外死亡睡互,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門陵像,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人寇壳,你說(shuō)我怎么就攤上這事醒颖。” “怎么了壳炎?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵泞歉,是天一觀的道長(zhǎng)逼侦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)腰耙,這世上最難降的妖魔是什么榛丢? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮挺庞,結(jié)果婚禮上晰赞,老公的妹妹穿的比我還像新娘。我一直安慰自己选侨,他們只是感情好掖鱼,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著援制,像睡著了一般戏挡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晨仑,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天褐墅,我揣著相機(jī)與錄音,去河邊找鬼洪己。 笑死妥凳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的码泛。 我是一名探鬼主播猾封,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼噪珊!你這毒婦竟也來(lái)了晌缘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤痢站,失蹤者是張志新(化名)和其女友劉穎磷箕,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阵难,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岳枷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呜叫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片空繁。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖朱庆,靈堂內(nèi)的尸體忽然破棺而出盛泡,到底是詐尸還是另有隱情,我是刑警寧澤娱颊,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布傲诵,位于F島的核電站凯砍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拴竹。R本人自食惡果不足惜悟衩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望栓拜。 院中可真熱鬧座泳,春花似錦、人聲如沸菱属。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纽门。三九已至薛耻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赏陵,已是汗流浹背饼齿。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝙搔,地道東北人缕溉。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像吃型,于是被迫代替她去往敵國(guó)和親证鸥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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

  • 普通創(chuàng)建對(duì)象和字面量創(chuàng)建對(duì)象不足之處:雖然 Object 構(gòu)造函數(shù)或?qū)ο笞置媪慷伎梢杂脕?lái)創(chuàng)建單個(gè)對(duì)象勤晚,但這些方式有...
    believedream閱讀 2,384評(píng)論 2 18
  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,238評(píng)論 0 4
  • 今天寫枉层?明天寫? 我遲疑不決赐写。 滿腹欣慰提筆鸟蜡,又只好悻悻刪除。 無(wú)力與絕望來(lái)得急促而又洶涌挺邀。 我記不得任何東西了揉忘。...
    與青云閱讀 312評(píng)論 0 0
  • 當(dāng)初我們上大學(xué)的時(shí)候,第一臺(tái)電腦買的是15寸的CRT顯示器端铛,當(dāng)時(shí)覺(jué)得挺不錯(cuò)的泣矛,在那個(gè)靠撥號(hào)上網(wǎng)的時(shí)期,能夠簡(jiǎn)單的敲...
    豪哥的世界閱讀 864評(píng)論 0 2
  • 9月28號(hào)禾蚕,遠(yuǎn)在歐洲的老板突然在微信上說(shuō)拿到了12個(gè)南山半馬的名額乳蓄。需要我在國(guó)慶之后,把具體名額發(fā)給他夕膀。這意味著我...
    多幣閱讀 301評(píng)論 2 1