摘要:所以,這篇文章將通過一段非常簡潔的等式,把當(dāng)中一個(gè)相對較難的知識(shí)點(diǎn),,和給串聯(lián)起來要理解當(dāng)中的這三個(gè)關(guān)鍵字,首先得弄清楚它們是用來干嘛的。方案讓吃掉,直接消化吸收的所有能力。
關(guān)于JS當(dāng)中的call,apply和bind,相信大家和我一樣,已經(jīng)看過了無數(shù)篇相關(guān)的文章,都有自己的理解。所以這篇文章并非什么科普類的文章,僅僅是把我自己的理解記錄下來。
我的學(xué)習(xí)習(xí)慣,是喜歡把各種看似孤立的知識(shí)點(diǎn)串聯(lián)起來,綜合理解并運(yùn)用,通過最簡單最直觀的思路把它理解透。所以,這篇文章將通過一段非常簡潔的等式,把JS當(dāng)中一個(gè)相對較難的知識(shí)點(diǎn),call,apply和bind給串聯(lián)起來:
cat.call(dog, a, b) = cat.apply(dog, [a, b]) = (cat.bind(dog, a, b))() = dog.cat(a, b)
要理解JS當(dāng)中的這三個(gè)關(guān)鍵字,首先得弄清楚它們是用來干嘛的。復(fù)雜些來說,可以引用MDN文檔的原文:
可以讓call()中的對象調(diào)用當(dāng)前對象所擁有的function。你可以使用call()來實(shí)現(xiàn)繼承:寫一個(gè)方法,然后讓另外一個(gè)新的對象來繼承它(而不是在新對象中再寫一次這個(gè)方法)。
簡單些來說,可以引用大家都看過的一句話:
為了動(dòng)態(tài)改變某個(gè)函數(shù)運(yùn)行時(shí)的上下文(context)。
又或者是
為了改變函數(shù)體內(nèi)部this的指向
上面這些解釋都很正確,說得一點(diǎn)問題都沒有,但是里面卻又引入了繼承,上下文,this這些額外的知識(shí)點(diǎn)。如果我只想用最直觀的辦法去理解這三個(gè)關(guān)鍵字的作用,也許可以這么去理解:
定義一個(gè)貓對象:
class Cat { constructor (name) { this.name = name } catchMouse(name1, name2) { console.log(`${this.name} caught 2 mouse! They call ${name1} and ${name2}.`) } }
這個(gè)貓對象擁有一個(gè)抓老鼠的技能catchMouse()。
然后類似的,定義一個(gè)狗對象:
class Dog { constructor (name) { this.name = name } biteCriminals(name1, name2) { console.log(`${this.name} bite 2 criminals! Their name is ${name1} and ${name2}.`) } }
這個(gè)狗對象能夠咬壞人biteCriminal()。
接下來,我們實(shí)例化兩個(gè)對象,分別得到一只叫“Kitty”的貓和叫“Doggy”的狗:
const kitty = new Cat("Kitty") const doggy = new Dog("Doggy")
首先讓它們彼此發(fā)揮自己的技能:
kitty.catchMouse("Mickey", "Minnie") // Kitty caught mouse! They call Mickey and Minnie. doggy.biteCriminal("Tom", "Jerry") // Doggy bite a criminal! Their name is Tom and Jerry.
現(xiàn)在,我們希望賦予Doggy抓老鼠的能力,如果不使用這三個(gè)關(guān)鍵字,應(yīng)該怎么做呢?
方案A:修改Dog對象,直接為其定義一個(gè)和Cat相同的抓老鼠技能。
方案B:讓Doggy吃掉Kitty,直接消化吸收Kitty的所有能力。
其實(shí)方案A和方案B的解決辦法是類似的,也是需要修改Dog對象,不過方案B會(huì)更簡單粗暴一點(diǎn):
class Dog { constructor (name, kitty) { this.name = name this.catchMouse = kitty.catchMouse } biteCriminals(name1, name2) { console.log(`${this.name} bite 2 criminals! Their name is ${name1} and ${name2}.`) } } const kitty = new Cat("Kitty") const doggy = new Dog("Doggy", kitty) doggy.catchMouse("Mickey", "Minnie") // Doggy caught 2 mouse! They call Mickey and Minnie.
上面這種方法實(shí)在是太不優(yōu)雅,往往很多時(shí)候在定義Dog對像的時(shí)候根本就沒有打算過要為它添加抓老鼠的方法。那么有沒有一種辦法能夠在不修改Dog對象內(nèi)容的前提下,讓Doggy實(shí)例也能夠擁有抓老鼠的辦法呢?答案就是使用call,apply或者bind關(guān)鍵字:
kitty.catchMouse.call(doggy, "Mickey", "Minnie") kitty.catchMouse.apply(doggy, ["Mickey", "Minnie"]) const doggyCatchMouse = kitty.catchMouse.bind(doggy, "Mickey", "Minnie") doggyCatchMouse() // Doggy caught 2 mouse! They call Mickey and Minnie. // Doggy caught 2 mouse! They call Mickey and Minnie. // Doggy caught 2 mouse! They call Mickey and Minnie.
反過來,讓Kitty擁有咬壞人的能力,也可以通過這種辦法實(shí)現(xiàn),讀者可以自行嘗試。
看到這里,相信讀者已經(jīng)能夠明白call,apply和bind的區(qū)別及作用,反過來再查看各自的概念,應(yīng)該也能夠更容易理解。
回到文章開頭的等式:
cat.call(dog, a, b) = cat.apply(dog, [a, b]) = (cat.bind(dog, a, b))() = dog.cat(a, b)
這里的“等號(hào)”其實(shí)并不嚴(yán)謹(jǐn),因?yàn)槿齻€(gè)關(guān)鍵字的區(qū)別及背后的原理肯定不是區(qū)區(qū)一個(gè)等號(hào)就能夠概括的,但是對于概念的理解以及實(shí)際情況下的運(yùn)用來說,這條等式未必不是一個(gè)好的思路。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93964.html
摘要:關(guān)于的指向的問題請參照我的學(xué)習(xí)筆記。那么在這里事實(shí)上都改變了函數(shù)方法被調(diào)用時(shí)的指向。那么回調(diào)函數(shù)在執(zhí)行的時(shí)候指向還是。大家看完之后應(yīng)該已經(jīng)懂了把還是不懂的話在評論區(qū)留言,我給大家解答。 先從一個(gè)小題目開始吧: 要實(shí)現(xiàn)一個(gè)加法函數(shù),這個(gè)時(shí)候向函數(shù)當(dāng)中傳遞個(gè)數(shù)大于0的若干個(gè)整形數(shù)據(jù),求所有這些數(shù)據(jù)的和。 Function.prototype.call Function.prototype...
摘要:目錄函數(shù)的聲明函數(shù)的屬性和方法函數(shù)的作用域閉包知識(shí)點(diǎn)小結(jié)關(guān)于函數(shù),可以從以下個(gè)方面去理解首先,數(shù)據(jù)類型上看函數(shù)在中是一種數(shù)據(jù)類型,是對象的一種其次,從功能上看函數(shù)本質(zhì)上是一段反復(fù)調(diào)用的代碼塊最后,從地位上看函數(shù)在中和其他基本數(shù)據(jù)類型一樣,可 目錄 1.函數(shù)的聲明 2.函數(shù)的屬性和方法 3.函數(shù)的作用域 4.閉包知識(shí)點(diǎn) 5.小結(jié) 關(guān)于函數(shù),可以從以下3個(gè)方面去理解:首先,數(shù)據(jù)類型上看:...
摘要:而當(dāng)做普通函數(shù)調(diào)用的話,實(shí)際上即第種情況下,對函數(shù)普通調(diào)用,此時(shí)的指向這是正常情況下,會(huì)正確返回并且指向該對象,但是在構(gòu)造函數(shù)當(dāng)中,如果返回了一個(gè)對象,那么會(huì)指向返回的那個(gè)對象。 this應(yīng)該是一個(gè)討論了很久的話題了。其中,關(guān)于this的文章,在很多的博客當(dāng)中也有很多介紹,但是,以前我都是一知半解的去了解它,就是看博客當(dāng)中,只介紹了一些情況下的 this 的使用方式,但是也并沒有自己去...
摘要:回顧一下關(guān)鍵詞的過程創(chuàng)建一個(gè)新的對象使得的指向構(gòu)造函數(shù)的原型對象執(zhí)行構(gòu)造函數(shù)中的,改變的指向?yàn)槿绻Y(jié)果是對象類型,則返回結(jié)果,否則返回指向的是調(diào)用時(shí)傳遞的第一個(gè)參數(shù)。 this = ? 在JS中,當(dāng)一個(gè)函數(shù)執(zhí)行時(shí),都會(huì)創(chuàng)建一個(gè)執(zhí)行上下文用來確認(rèn)當(dāng)前函數(shù)的執(zhí)行環(huán)境,執(zhí)行上下文分為 全局執(zhí)行上下文和 函數(shù)執(zhí)行上下文。而 this 就是指向這個(gè)執(zhí)行上下文的對象。所以,this是在運(yùn)行時(shí)決定的...
摘要:原文鏈接參考深入理解原型和閉包完結(jié)王福朋博客園中的作用域詳解博客園 前言 王福朋老師的 JavaScript原型和閉包系列 文章看了不下三遍了,最為一個(gè)初學(xué)者,每次看的時(shí)候都會(huì)有一種 大徹大悟 的感覺,而看完之后卻總是一臉懵逼。原型與閉包 可以說是 JavaScirpt 中理解起來最難的部分了,當(dāng)然,我也只是了解到了一些皮毛,對于 JavaScript OOP 更是缺乏經(jīng)驗(yàn)。這里我想總...
閱讀 653·2021-11-25 09:43
閱讀 1926·2021-11-17 09:33
閱讀 839·2021-09-07 09:58
閱讀 2072·2021-08-16 10:52
閱讀 493·2019-08-30 15:52
閱讀 1735·2019-08-30 15:43
閱讀 1005·2019-08-30 15:43
閱讀 2938·2019-08-29 16:41