JS基礎回顧:方法/apply/call

一席纽、方法

在一個對象中綁定函數(shù),稱為這個對象的方法撞蚕。

在JavaScript中润梯,對象的定義是這樣的:

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

但是陋葡,如果我們給xiaoming綁定一個函數(shù)侣颂,就可以做更多的事情譬涡。比如矾睦,寫個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(); // 今年調用是27,明年調用就變成28了

綁定到對象上的函數(shù)稱為方法囤捻,和普通函數(shù)也沒啥區(qū)別评抚,但是它在內部使用了一個this關鍵字熟空,這個東東是什么谦秧?

★在一個方法內部竟纳,this是一個特殊變量,它始終指向當前對象疚鲤,也就是xiaoming這個變量锥累。所以,this.birth可以拿到xiaoming的birth屬性集歇。

讓我們拆開寫:

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

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

xiaoming.age(); // 27, 正常結果
getAge(); // NaN

【注意】M奥浴!诲宇!單獨調用函數(shù)getAge()怎么返回了NaN际歼?請注意,我們已經進入到了JavaScript的一個大坑里姑蓝。

JavaScript的函數(shù)內部如果調用了this鹅心,那么這個this到底指向誰?
答案是纺荧,視情況而定巴帮!

如果以對象的方法形式調用溯泣,比如xiaoming.age(),該函數(shù)的this指向被調用的對象榕茧,也就是xiaoming垃沦,這是符合我們預期的。

如果單獨調用函數(shù)用押,比如getAge()肢簿,此時,該函數(shù)的this指向全局對象蜻拨,也就是window池充。

坑爹啊缎讼!

更坑爹的是收夸,如果這么寫:

var fn = xiaoming.age; // 先拿到xiaoming的age函數(shù)
fn(); // NaN

也是不行的!

★★★要保證this指向正確血崭,必須用obj.xxx()的形式調用卧惜!

由于這是一個巨大的設計錯誤,要想糾正可沒那么簡單夹纫。★ECMA決定咽瓷,在strict模式下讓函數(shù)的this指向undefined,因此舰讹,在strict模式下茅姜,你會得到一個錯誤:

'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

這個決定只是讓錯誤及時暴露出來,并沒有解決this應該指向的正確位置月匣。

有些時候钻洒,喜歡重構的你把方法重構了一下:

'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

結果又報錯了!原因是this指針只在age方法的函數(shù)內指向xiaoming锄开,在函數(shù)內部定義的函數(shù)素标,this又指向undefined了!(在非strict模式下院刁,它重新指向全局對象windowE锤啤)

修復的辦法

我們★★★用一個that變量首先捕獲this:

'use strict';

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

xiaoming.age(); // 27

用var that = this;粪狼,你就可以放心地在方法內部定義其他函數(shù)退腥,而不是把所有語句都堆到一個方法中。

二再榄、apply

雖然在一個獨立的函數(shù)調用中狡刘,根據是否是strict模式,this指向undefined或window困鸥,不過嗅蔬,我們還是可以控制this的指向的剑按!

要指定函數(shù)的this指向哪個對象,可以用★函數(shù)本身的apply方法.

它接收兩個參數(shù)澜术,★第一個參數(shù)就是需要綁定的this變量艺蝴,第二個參數(shù)是Array,表示函數(shù)本身的參數(shù)鸟废。

用apply修復getAge()調用:

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

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

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

三猜敢、call

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

** apply()把參數(shù)打包成Array再傳入盒延;**

** call()把參數(shù)按順序傳入缩擂。**

比如調用Math.max(3, 5, 4),分別用apply()和call()實現(xiàn)如下:

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
對普通函數(shù)調用添寺,我們通常把this綁定為null胯盯。

四、裝飾器

利用apply()计露,我們還可以動態(tài)改變函數(shù)的行為博脑。

JavaScript的所有對象都是動態(tài)的,即使內置的函數(shù)薄坏,我們也可以重新指向新的函數(shù)趋厉。

現(xiàn)在假定我們想統(tǒng)計一下代碼一共調用了多少次parseInt(),可以把所有的調用都找出來胶坠,然后手動加上count += 1君账,不過這樣做太傻了。最佳方案是用我們自己的函數(shù)替換掉默認的parseInt():

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

window.parseInt = function () {
    count += 1;
    return oldParseInt.apply(null, arguments); // 調用原函數(shù)
};

// 測試:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3

原文鏈接:http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345005399057070809cfaa347dfb7207900cfd116fb000

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末沈善,一起剝皮案震驚了整個濱河市乡数,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闻牡,老刑警劉巖净赴,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異罩润,居然都是意外死亡玖翅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門割以,熙熙樓的掌柜王于貴愁眉苦臉地迎上來金度,“玉大人,你說我怎么就攤上這事严沥〔录” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵消玄,是天一觀的道長跟伏。 經常有香客問我丢胚,道長,這世上最難降的妖魔是什么受扳? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任携龟,我火速辦了婚禮,結果婚禮上勘高,老公的妹妹穿的比我還像新娘骨宠。我一直安慰自己,他們只是感情好相满,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布层亿。 她就那樣靜靜地躺著,像睡著了一般立美。 火紅的嫁衣襯著肌膚如雪匿又。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天建蹄,我揣著相機與錄音碌更,去河邊找鬼。 笑死洞慎,一個胖子當著我的面吹牛痛单,可吹牛的內容都是我干的。 我是一名探鬼主播劲腿,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼旭绒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了焦人?” 一聲冷哼從身側響起挥吵,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎花椭,沒想到半個月后忽匈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡矿辽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年丹允,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袋倔。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡雕蔽,死狀恐怖,靈堂內的尸體忽然破棺而出奕污,到底是詐尸還是另有隱情萎羔,我是刑警寧澤液走,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布碳默,位于F島的核電站贾陷,受9級特大地震影響,放射性物質發(fā)生泄漏嘱根。R本人自食惡果不足惜髓废,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望该抒。 院中可真熱鬧慌洪,春花似錦、人聲如沸凑保。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欧引。三九已至频伤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芝此,已是汗流浹背憋肖。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留婚苹,地道東北人岸更。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像膊升,于是被迫代替她去往敵國和親怎炊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內容