摘要:的調(diào)用者,將會(huì)指向這個(gè)對(duì)象。此外,還可以擴(kuò)展自己的其他方法。的使用最后來說說。不同的是,方法的返回值是函數(shù),并且需要稍后調(diào)用,才會(huì)執(zhí)行。而和則是立即調(diào)用??偨Y(jié)和的主要作用,是改變對(duì)象的執(zhí)行上下文,并且是立即執(zhí)行的。
前言
上一篇文章 《「前端面試題系列4」this 的原理以及用法》 中,提到了 call 和 apply。
它們最主要的作用,是改變 this 的指向。在平時(shí)的工作中,除了在寫一些基礎(chǔ)類,或者公用庫(kù)方法的時(shí)候會(huì)用到它們,其他時(shí)候 call 和 apply 的應(yīng)用場(chǎng)景并不多。
不過,突然遇到的時(shí)候,需要想一下才能轉(zhuǎn)過彎來。所以今天,就讓我們好好地探究一下,這兩個(gè)方法的區(qū)別以及一些妙用。最后,還會(huì)介紹與之用法相似的 bind 的方法。
call 和 apply 的共同點(diǎn)它們的共同點(diǎn)是,都能夠改變函數(shù)執(zhí)行時(shí)的上下文,將一個(gè)對(duì)象的方法交給另一個(gè)對(duì)象來執(zhí)行,并且是立即執(zhí)行的。
為何要改變執(zhí)行上下文?舉一個(gè)生活中的小例子:平時(shí)沒時(shí)間做飯的我,周末想給孩子燉個(gè)腌篤鮮嘗嘗。但是沒有適合的鍋,而我又不想出去買。所以就問鄰居借了一個(gè)鍋來用,這樣既達(dá)到了目的,又節(jié)省了開支,一舉兩得。
改變執(zhí)行上下文也是一樣的,A 對(duì)象有一個(gè)方法,而 B 對(duì)象因?yàn)槟撤N原因,也需要用到同樣的方法,那么這時(shí)候我們是多帶帶為 B 對(duì)象擴(kuò)展一個(gè)方法呢,還是借用一下 A 對(duì)象的方法呢?當(dāng)然是借用 A 對(duì)象的啦,既完成了需求,又減少了內(nèi)存的占用。
另外,它們的寫法也很類似,調(diào)用 call 和 apply 的對(duì)象,必須是一個(gè)函數(shù) Function。接下來,就會(huì)說到具體的寫法,那也是它們區(qū)別的主要體現(xiàn)。
call 和 apply 的區(qū)別它們的區(qū)別,主要體現(xiàn)在參數(shù)的寫法上。先來看一下它們各自的具體寫法。
call 的寫法Function.call(obj,[param1[,param2[,…[,paramN]]]])
需要注意以下幾點(diǎn):
調(diào)用 call 的對(duì)象,必須是個(gè)函數(shù) Function。
call 的第一個(gè)參數(shù),是一個(gè)對(duì)象。 Function 的調(diào)用者,將會(huì)指向這個(gè)對(duì)象。如果不傳,則默認(rèn)為全局對(duì)象 window。
第二個(gè)參數(shù)開始,可以接收任意個(gè)參數(shù)。每個(gè)參數(shù)會(huì)映射到相應(yīng)位置的 Function 的參數(shù)上。但是如果將所有的參數(shù)作為數(shù)組傳入,它們會(huì)作為一個(gè)整體映射到 Function 對(duì)應(yīng)的第一個(gè)參數(shù)上,之后參數(shù)都為空。
function func (a,b,c) {} func.call(obj, 1,2,3) // func 接收到的參數(shù)實(shí)際上是 1,2,3 func.call(obj, [1,2,3]) // func 接收到的參數(shù)實(shí)際上是 [1,2,3],undefined,undefinedapply 的寫法
Function.apply(obj[,argArray])
需要注意的是:
它的調(diào)用者必須是函數(shù) Function,并且只接收兩個(gè)參數(shù),第一個(gè)參數(shù)的規(guī)則與 call 一致。
第二個(gè)參數(shù),必須是數(shù)組或者類數(shù)組,它們會(huì)被轉(zhuǎn)換成類數(shù)組,傳入 Function 中,并且會(huì)被映射到 Function 對(duì)應(yīng)的參數(shù)上。這也是 call 和 apply 之間,很重要的一個(gè)區(qū)別。
func.apply(obj, [1,2,3]) // func 接收到的參數(shù)實(shí)際上是 1,2,3 func.apply(obj, { 0: 1, 1: 2, 2: 3, length: 3 }) // func 接收到的參數(shù)實(shí)際上是 1,2,3什么是類數(shù)組?
先說數(shù)組,這我們都熟悉。它的特征有:可以通過角標(biāo)調(diào)用,如 array[0];具有長(zhǎng)度屬性length;可以通過 for 循環(huán)或forEach方法,進(jìn)行遍歷。
那么,類數(shù)組是什么呢?顧名思義,就是具備與數(shù)組特征類似的對(duì)象。比如,下面的這個(gè)對(duì)象,就是一個(gè)類數(shù)組。
let arrayLike = { 0: 1, 1: 2, 2: 3, length: 3 };
類數(shù)組 arrayLike 可以通過角標(biāo)進(jìn)行調(diào)用,具有l(wèi)ength屬性,同時(shí)也可以通過 for 循環(huán)進(jìn)行遍歷。
類數(shù)組,還是比較常用的,只是我們平時(shí)可能沒注意到。比如,我們獲取 DOM 節(jié)點(diǎn)的方法,返回的就是一個(gè)類數(shù)組。再比如,在一個(gè)方法中使用 arguments 獲取到的所有參數(shù),也是一個(gè)類數(shù)組。
但是需要注意的是:類數(shù)組無法使用 forEach、splice、push 等數(shù)組原型鏈上的方法,畢竟它不是真正的數(shù)組。
call 和 apply 的用途下面會(huì)分別列舉 call 和 apply 的一些使用場(chǎng)景。聲明:例子中沒有哪個(gè)場(chǎng)景是必須用 call 或者必須用 apply 的,只是個(gè)人習(xí)慣這么用而已。
call 的使用場(chǎng)景1、對(duì)象的繼承。如下面這個(gè)例子:
function superClass () { this.a = 1; this.print = function () { console.log(this.a); } } function subClass () { superClass.call(this); this.print(); } subClass(); // 1
subClass 通過 call 方法,繼承了 superClass 的 print 方法和 a 變量。此外,subClass 還可以擴(kuò)展自己的其他方法。
2、借用方法。還記得剛才的類數(shù)組么?如果它想使用 Array 原型鏈上的方法,可以這樣:
let domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
這樣,domNodes 就可以應(yīng)用 Array 下的所有方法了。
apply 的一些妙用1、Math.max。用它來獲取數(shù)組中最大的一項(xiàng)。
let max = Math.max.apply(null, array);
同理,要獲取數(shù)組中最小的一項(xiàng),可以這樣:
let min = Math.min.apply(null, array);
2、實(shí)現(xiàn)兩個(gè)數(shù)組合并。在 ES6 的擴(kuò)展運(yùn)算符出現(xiàn)之前,我們可以用 Array.prototype.push來實(shí)現(xiàn)。
let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; Array.prototype.push.apply(arr1, arr2); console.log(arr1); // [1, 2, 3, 4, 5, 6]bind 的使用
最后來說說 bind。在 MDN 上的解釋是:bind() 方法創(chuàng)建一個(gè)新的函數(shù),在調(diào)用時(shí)設(shè)置 this 關(guān)鍵字為提供的值。并在調(diào)用新函數(shù)時(shí),將給定參數(shù)列表作為原函數(shù)的參數(shù)序列的前若干項(xiàng)。
它的語法如下:
Function.bind(thisArg[, arg1[, arg2[, ...]]])
bind 方法 與 apply 和 call 比較類似,也能改變函數(shù)體內(nèi)的 this 指向。不同的是,bind 方法的返回值是函數(shù),并且需要稍后調(diào)用,才會(huì)執(zhí)行。而 apply 和 call 則是立即調(diào)用。
來看下面這個(gè)例子:
function add (a, b) { return a + b; } function sub (a, b) { return a - b; } add.bind(sub, 5, 3); // 這時(shí),并不會(huì)返回 8 add.bind(sub, 5, 3)(); // 調(diào)用后,返回 8
如果 bind 的第一個(gè)參數(shù)是 null 或者 undefined,this 就指向全局對(duì)象 window。
總結(jié)call 和 apply 的主要作用,是改變對(duì)象的執(zhí)行上下文,并且是立即執(zhí)行的。它們?cè)趨?shù)上的寫法略有區(qū)別。
bind 也能改變對(duì)象的執(zhí)行上下文,它與 call 和 apply 不同的是,返回值是一個(gè)函數(shù),并且需要稍后再調(diào)用一下,才會(huì)執(zhí)行。
最后,分享一個(gè)在知乎上看到的,關(guān)于 call 和 apply 的便捷記憶法:
貓吃魚,狗吃肉,奧特曼打小怪獸。有天狗想吃魚了
貓.吃魚.call(狗,魚)
狗就吃到魚了
貓成精了,想打怪獸
奧特曼.打小怪獸.call(貓,小怪獸)
貓也可以打小怪獸了
PS:歡迎關(guān)注我的公眾號(hào) “超哥前端小?!?,交流更多的想法與技術(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/108876.html
摘要:原題如下寫一個(gè)方法,當(dāng)使用下面的語法調(diào)用時(shí),能正常工作這道題要考察的,就是對(duì)函數(shù)柯里化的理解。當(dāng)參數(shù)只有一個(gè)的時(shí)候,進(jìn)行柯里化的處理。這其實(shí)就是函數(shù)柯里化的簡(jiǎn)單應(yīng)用。 showImg(https://segmentfault.com/img/bVbopGm?w=620&h=350); 前言 這是前端面試題系列的第 6 篇,你可能錯(cuò)過了前面的篇章,可以在這里找到: ES6 中箭頭函數(shù)的...
摘要:會(huì)創(chuàng)建一個(gè)新的函數(shù),成為綁定函數(shù),目標(biāo)函數(shù)和綁定函數(shù)有共同的函數(shù)體。新的目標(biāo)函數(shù)被調(diào)用的時(shí)候,就會(huì)綁定到函數(shù)的第一個(gè)參數(shù)上,且該參數(shù)不能被重寫。當(dāng)新的目標(biāo)函數(shù)被創(chuàng)建的時(shí)候,目標(biāo)函數(shù)的的值通過被設(shè)成了傳入的參數(shù)的值。 bind 概述 bind方法是綁定在了Function.prototype上。這個(gè)方法會(huì)創(chuàng)建一個(gè)新的函數(shù),當(dāng)被調(diào)用時(shí),會(huì)將其this關(guān)鍵字,設(shè)置為一個(gè)提供的值。 bind(...
摘要:理解文章中已經(jīng)比較全面的分析了在中的指向問題,用一句話來總結(jié)就是的指向一定是在執(zhí)行時(shí)決定的,指向被調(diào)用函數(shù)的對(duì)象。與和直接執(zhí)行原函數(shù)不同的是,返回的是一個(gè)新函數(shù)。這個(gè)新函數(shù)包裹了原函數(shù),并且綁定了的指向?yàn)閭魅氲摹? 理解 JavaScript this 文章中已經(jīng)比較全面的分析了 this 在 JavaScript 中的指向問題,用一句話來總結(jié)就是:this 的指向一定是在執(zhí)行時(shí)決定的,...
摘要:和類似,都是調(diào)用函數(shù),并指定函數(shù)的值和參數(shù),區(qū)別在于傳入?yún)?shù)是通過參數(shù)列表的形式,傳入?yún)?shù)是通過數(shù)組的形式方法與前兩個(gè)不同,它創(chuàng)建一個(gè)新的函數(shù),在調(diào)用新函數(shù)時(shí),會(huì)調(diào)用原函數(shù),并指定原函數(shù)的值和參數(shù)。執(zhí)行的時(shí)候并沒有調(diào)用函數(shù)。 簡(jiǎn)介 JavaScript 中有三個(gè)方法Function.prototype.call()、Function.prototype.apply()和Function...
摘要:綁定函數(shù)被調(diào)用時(shí),也接受預(yù)設(shè)的參數(shù)提供給原函數(shù)。一個(gè)綁定函數(shù)也能使用操作符創(chuàng)建對(duì)象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。 一直很難理解js中的call apply bind,在w3schools,mdn閱讀了,也看了很多相關(guān)的文章,今天我來寫下我理解的call apply bind 首先創(chuàng)建一個(gè)函數(shù) function man(){} man.prototype = { name: ...
閱讀 2832·2023-04-25 18:58
閱讀 977·2021-11-25 09:43
閱讀 1210·2021-10-25 09:46
閱讀 3494·2021-09-09 11:40
閱讀 1679·2021-08-05 09:59
閱讀 869·2019-08-29 15:07
閱讀 956·2019-08-29 12:48
閱讀 695·2019-08-29 11:19