方法 (this、apply、call拴签、裝飾器)

在一個(gè)對象中綁定函數(shù)孝常,稱為這個(gè)對象的方法。

在 JavaScript 中蚓哩,對象的定義是這樣的:

var xiaoming = {
    name: '小明',
    birth: 1990
};

我們給 xiaoming 綁定一個(gè)函數(shù)构灸,就可以做更多的事情。比如岸梨,寫個(gè) age() 方法喜颁,返回 xiaoming 的年齡:

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 26

綁定到對象上的函數(shù)稱為 方法,和普通函數(shù)也沒啥區(qū)別曹阔,但是它在內(nèi)部使用了一個(gè) this 關(guān)鍵字半开,這個(gè)東東是什么?

在一個(gè)方法內(nèi)部赃份,this 是一個(gè)特殊變量寂拆,它始終指向當(dāng)前對象,也就是 xiaoming 這個(gè)變量抓韩。 所以纠永,this.birth 可以拿到 xiaomingbirth 屬性。

讓我們拆開寫:

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 26, 正常結(jié)果
getAge(); // NaN

如果以對象的方法形式調(diào)用谒拴,比如 xiaoming.age()尝江,該函數(shù)的 this 指向被調(diào)用的對象,也就是 xiaoming英上,這是符合我們預(yù)期的炭序。

如果單獨(dú)調(diào)用函數(shù),比如 getAge()善延,此時(shí)少态,該函數(shù)的 this 指向全局對象,也就是 window易遣,所以單獨(dú)調(diào)用函數(shù) getAge() 返回了 NaN。

要保證 this 指向正確嫌佑,必須用 obj.xxx() 的形式調(diào)用豆茫!

由于這是一個(gè)巨大的設(shè)計(jì)錯(cuò)誤,要想糾正可沒那么簡單屋摇。ECMA 決定揩魂,在 strict 模式下讓函數(shù)的 this 指向 undefined,因此炮温,在 strict 模式下火脉,你會(huì)得到一個(gè)錯(cuò)誤:

'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

var fn = xiaoming.age;
fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined

但這只是讓錯(cuò)誤及時(shí)暴露出來,并沒有解決 this 應(yīng)該指向的正確位置。

再看另一個(gè)例子倦挂,我們把上面的方法重構(gòu)了一下:

'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined

結(jié)果又報(bào)錯(cuò)了畸颅!原因是 this 指針只在 age 方法的函數(shù)內(nèi)指向 xiaoming,在函數(shù)內(nèi)部定義的函數(shù)方援,this 又指向 undefined 了C怀础(在非 strict 模式下,它重新指向全局對象 window7赶贰)

修復(fù)的辦法也不是沒有送火,我們用一個(gè) that 變量首先捕獲 this

'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var that = this; // 在方法內(nèi)部一開始就捕獲this
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - that.birth; // 用that而不是this
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); // 26




apply

雖然在一個(gè)獨(dú)立的函數(shù)調(diào)用中,根據(jù)是否是 strict 模式先匪,this 指向 undefinedwindow种吸,不過,我們還是可以控制 this 的指向的呀非!

要指定函數(shù)的 this 指向哪個(gè)對象坚俗,可以用函數(shù)本身的 apply() 方法,它接收兩個(gè)參數(shù)姜钳,第一個(gè)參數(shù)就是需要綁定的 this 變量坦冠,第二個(gè)參數(shù)是 Array,表示函數(shù)本身的參數(shù)哥桥。

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 26
getAge.apply(xiaoming, []); // 26, this指向xiaoming, 參數(shù)為空

使用參數(shù)的情況見下例:

function getAge(y) {
    // var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

getAge.apply(xiaoming, [2016]); // 26辙浑,傳入?yún)?shù)2016

另一個(gè)與 apply() 類似的方法是 call(),唯一區(qū)別是:

apply() 把參數(shù)打包成 Array 再傳入拟糕;call() 把參數(shù)按順序傳入判呕。

getAge.call(xiaoming, 2016); // 26

傳入多個(gè)參數(shù)見下例:

function getAge(i, j, k) {
    console.log(i + '年,小明' + (i - this.birth) + '歲送滞。');
    console.log(j + '年侠草,小明' + (j - this.birth) + '歲。');
    console.log(k + '年犁嗅,小明' + (k - this.birth) + '歲边涕。');
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

getAge.apply(xiaoming,[2014,2015,2016])
2014年,小明24歲褂微。
2015年功蜓,小明25歲。
2016年宠蚂,小明26歲式撼。

getAge.call(xiaoming,2014,2015,2016)
2014年,小明24歲求厕。
2015年著隆,小明25歲扰楼。
2016年,小明26歲美浦。




裝飾器

利用 apply()弦赖,我們還可以動(dòng)態(tài)改變函數(shù)的行為。

JavaScript 的所有對象都是動(dòng)態(tài)的抵代,即使內(nèi)置的函數(shù)腾节,我們也可以重新指向新的函數(shù)。

現(xiàn)在假定我們想統(tǒng)計(jì)一下代碼一共調(diào)用了多少次 parseInt()荤牍,我們手動(dòng)在 paeselnt() 函數(shù)內(nèi)部拯救一個(gè) count 變量案腺,來統(tǒng)計(jì)被調(diào)用是次數(shù):

var count = 0;
var oldParseInt = parseInt; // 保存原函數(shù)

window.parseInt = function () {
    count += 1;  // 統(tǒng)計(jì)調(diào)用次數(shù)
    return oldParseInt.apply(null, arguments); // 調(diào)用原函數(shù)
};

// 測試:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市康吵,隨后出現(xiàn)的幾起案子劈榨,更是在濱河造成了極大的恐慌,老刑警劉巖晦嵌,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件同辣,死亡現(xiàn)場離奇詭異,居然都是意外死亡惭载,警方通過查閱死者的電腦和手機(jī)旱函,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來描滔,“玉大人棒妨,你說我怎么就攤上這事『ぃ” “怎么了券腔?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拘泞。 經(jīng)常有香客問我纷纫,道長,這世上最難降的妖魔是什么陪腌? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任辱魁,我火速辦了婚禮,結(jié)果婚禮上诗鸭,老公的妹妹穿的比我還像新娘商叹。我一直安慰自己,他們只是感情好只泼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卵洗,像睡著了一般请唱。 火紅的嫁衣襯著肌膚如雪弥咪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天十绑,我揣著相機(jī)與錄音聚至,去河邊找鬼。 笑死本橙,一個(gè)胖子當(dāng)著我的面吹牛扳躬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甚亭,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贷币,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了亏狰?” 一聲冷哼從身側(cè)響起役纹,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暇唾,沒想到半個(gè)月后促脉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡策州,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年瘸味,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片够挂。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旁仿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出下硕,到底是詐尸還是另有隱情丁逝,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布梭姓,位于F島的核電站,受9級(jí)特大地震影響誉尖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜琢感,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一驹针、第九天 我趴在偏房一處隱蔽的房頂上張望诀艰。 院中可真熱鬧,春花似錦苛蒲、人聲如沸臂外。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漾肮。三九已至,卻和暖如春忱辅,著一層夾襖步出監(jiān)牢的瞬間谭溉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柜与,地道東北人弄匕。 一個(gè)月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓迁匠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親城丧。 傳聞我的和親對象是個(gè)殘疾皇子亡哄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

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

  • 特別說明擦酌,為便于查閱赊舶,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 691評論 0 1
  • 1. this之謎 在JavaScript中笼平,this是當(dāng)前執(zhí)行函數(shù)的上下文舔痪。因?yàn)镴avaScript有4種不同的...
    百里少龍閱讀 999評論 0 3
  • 參考 學(xué)習(xí)網(wǎng)站 廖雪峰的JavaScript教程 w3cshool 阮一峰的JavaScript全棧工程師培訓(xùn)教程...
    HuangJn閱讀 341評論 0 1
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,234評論 0 4
  • 今天加班,把老大昨天的博物館方案變成rhino模型滋捶,本來是不難的工作,但是就是塌不下心來去做载萌。 嗯巡扇,說是不難厅翔,其實(shí)...
    ccshark閱讀 162評論 0 0