<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
apply、call和bind都是系統提供給我們的內建方法,每個函數都可以使用這三種方法,是因為apply、call和bind都實現在了Function的原型上(Function.prototype),而他們的作用都是給我們函數呼叫時顯式繫結上this。下面先介紹一下它們的基本用法:
apply方法:呼叫一個具有給定this值的函數,以及以一個陣列(或類陣列物件)的形式提供的引數。
使用語法:func.apply(thisArg, [argsArray])
thisArg:在func函數呼叫時繫結的this值;[argsArray]:一個陣列或者類陣列物件,其中的陣列元素將作為單獨的引數傳給func函數;
使用效果:
function foo(x, y ,z) { console.log(this, x, y, z) } const obj = { name: 'curry', age: 30 } /** * 1.將obj物件繫結給foo函數的this * 2.陣列中的1 2 3分別傳遞給foo函數對應的三個引數 */ foo.apply(obj, [1, 2, 3])
call方法:使用一個指定的 this值和單獨給出的一個或多個引數來呼叫一個函數。
使用語法:func.call(thisArg, arg1, arg2, ...)
thisArg:在func函數呼叫時繫結的this值;arg1, arg2, ...:指定的參數列,將作為引數傳遞給func函數;
使用效果:
function foo(x, y ,z) { console.log(this, x, y, z) } const obj = { name: 'curry', age: 30 } /** * 1.將obj物件繫結給foo函數的this * 2.call剩餘引數中的a b c分別傳遞給foo函數對應的三個引數 */ foo.call(obj, 'a', 'b', 'c')
bind方法:建立一個新的函數,在bind()被呼叫時,這個新函數的this被指定為bind()的第一個引數,而其餘引數將作為新函數的引數,供呼叫時使用。
使用語法:func.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg:呼叫func函數時作為this引數傳遞給目標函數的值;arg1, arg2, ...:當目標函數被呼叫時,被預置入func函數的參數列中的引數;
使用效果:
function foo(...args) { console.log(this, ...args) } const obj = { name: 'curry', age: 30 } /** * 1.將obj物件繫結給foo函數的this * 2.bind剩餘引數中的1 2 3分別傳遞給foo函數中引數 * 3.也可在newFoo呼叫時傳入引數,這時bind傳遞的引數會與newFoo呼叫時傳遞的引數進行合併 */ const newFoo = foo.bind(obj, 1, 2, 3) newFoo() newFoo('a', 'b', 'c')
總結:
apply和call主要用於在函數呼叫時給函數的this繫結對應的值,兩者作用類似,主要區別就是除了第一個引數,apply方法接受的是一個引數陣列,而call方法接受的是參數列。
bind也是給函數指定this所繫結的值,不同於apply和call的是,它會返回一個新的函數,新函數中的this指向就是我們所指定的值,且分別傳入的引數會進行合併。
為了所有定義的函數能夠使用我們自定義的apply、call和bind方法,所以需要將自己實現的方法掛在Function的原型上,這樣所有的函數就可以通過原型鏈找到自定義的這三個方法了。
Function.prototype.myApply = function(thisArg, argArray) { // 1.獲取當前需要被執行的函數 // 因為myApply是需要被當前函數進行呼叫的,根據this的隱式繫結,此處的this就是指向當前需要被執行的函數 const fn = this // 2.對傳入的thisArg進行邊界判斷 if (thisArg === null || thisArg === undefined) { // 當傳入的是null或者undefined是,被執行函數的this直接指向全域性window thisArg = window } else { // 將傳入的thisArg物件化,方便後面在thisArg新增屬性 thisArg = Object(thisArg) } // 也可簡單寫成三元運運算元: // thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg) // 3.將獲取的fn新增到thisArg物件上 // 這裡使用Symbol的原因是避免外部傳入的thisArg中的屬性與新增fn有衝突 const fnSymbol = Symbol() Object.defineProperty(thisArg, fnSymbol, { enumerable: false, configurable: true, writable: false, value: fn }) // 也可簡單寫成 // thisArg[fnSymbol] = fn // 4.對argArray進行判斷 // 看是否有傳入值,沒有值傳入就預設 [] argArray = argArray || [] // 5.呼叫獲取的fn函數,並將對應傳入的陣列展開傳遞過去 const result = thisArg[fnSymbol](...argArray) // 呼叫完後刪除新增的屬性 delete thisArg[fnSymbol] // 6.將結果返回 return result }
測試:雖然列印出來的物件中還存在Symbol屬性,實際上已經通過delete刪除了,這裡是物件參照的問題。
function foo(x, y, z) { console.log(this, x, y, z) } foo.myApply({name: 'curry'}, [1, 2, 3])
call方法的實現和apply方法的實現差不多,主要在於後面引數的處理。
Function.prototype.myCall = function(thisArg, ...args) { // 1.獲取當前需要被執行的函數 const fn = this // 2.對傳入的thisArg進行邊界判斷 thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg) // 3.將獲取的fn新增到thisArg物件上 const fnSymbol = Symbol() thisArg[fnSymbol] = fn // 4.呼叫獲取的fn函數,並將對應傳入的args傳遞過去 const result = thisArg[fnSymbol](...args) // 呼叫完後刪除新增的屬性 delete thisArg[fnSymbol] // 5.將結果返回 return result }
測試:
function foo(x, y, z) { console.log(this, x, y, z) } foo.myCall({name: 'curry'}, 1, 2, 3)
bind方法的實現稍微複雜一點,需要考慮到引數合併的問題。
Function.prototype.myBind = function(thisArg, ...argsArray) { // 1.獲取當前的目標函數,也就是當前使用myBind方法的函數 const fn = this // 2.對傳入的thisArg進行邊界判斷 thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg) // 3.將獲取的fn新增到thisArg物件上 const fnSymbol = Symbol() thisArg[fnSymbol] = fn // 4.定義一個新的函數 function newFn(...args) { // 4.1.合併myBind和newFn傳入的引數 const allArgs = [...argsArray, ...args] // 4.2.呼叫真正需要被呼叫的函數,並將合併後的引數傳遞過去 const result = thisArg[fnSymbol](...allArgs) // 4.3.呼叫完後刪除新增的屬性 delete thisArg[fnSymbol] // 4.4.將結果返回 return result } // 6.將新函數返回 return newFn }
測試:
function foo(x, y, z) { console.log(this, x, y, z) } const newFoo = foo.myBind({ name: 'curry' }, 1, 2) newFoo(3)
到此這篇關於使用JS簡單實現apply、call和bind方法的文章就介紹到這了,更多相關JS實現apply、call和bind方法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45