摘要:我是前端我的全名是我是一個前端指向接收多個參數,第一個是返回值返回值是一個函數上下文的,不會立即執行。柯里化相關講解請移步簡版的實現就算完成了歡迎吐槽點贊
它們有什么不同?怎么用?
call 接收多個參數,第一個為函數上下文也就是this,后邊參數為函數本身的參數。
let obj = { name: "一個" } function allName(firstName, lastName) { console.log(this) console.log(`我的全名是“${firstName}${this.name}${lastName}”`) } // 很明顯此時allName函數是沒有name屬性的 allName("我是", "前端") //我的全名是“我是前端” this指向window allName.call(obj, "我是", "前端") //我的全名是“我是一個前端” this指向objapply
apply接收兩個參數,第一個參數為函數上下文this,第二個參數為函數參數只不過是通過一個數組的形式傳入的。
allName.apply(obj, ["我是", "前端"])//我的全名是“我是一個前端” this指向objbind
bind 接收多個參數,第一個是bind返回值返回值是一個函數上下文的this,不會立即執行。
let obj = { name: "一個" } function allName(firstName, lastName, flag) { console.log(this) console.log(`我的全名是"${firstName}${this.name}${lastName}"我的座右銘是"${flag}"`) } allName.bind(obj) //不會執行 let fn = allName.bind(obj) fn("我是", "前端", "好好學習天天向上") // 也可以這樣用,參數可以分開傳。bind后的函數參數默認排列在原函數參數后邊 fn = allName.bind(obj, "你是") fn("前端", "好好學習天天向上")
接下來搓搓手實現call、apply和bind
實現calllet Person = { name: "Tom", say() { console.log(this) console.log(`我叫${this.name}`) } } // 先看代碼執行效果 Person.say() //我叫Tom Person1 = { name: "Tom1" } // 我們嘗試用原生方法call來實現this指向Person1 Person.say.call(Person1) //我叫Tom1
通過第一次打印執行和第二次打印執行我發現,如果Person1有say方法那么Person1直接執行Person1.say() 結果就是我是Tom1,是的call就是這么實現的。
再看代碼
Function.prototype.MyCall = function(context) { //context就是demo中的Person1 // 必須此時調用MyCall的函數是say方法,那么我們只需要在context上擴展一個say方法指向調用MyCall的say方法這樣this console.log(this) context.say = this //Mycall里邊的this就是我們虛擬的say方法 context.say() } // 測試 Person.say.MyCall(Person1)//我叫Tom1
perfect!爆棚的滿足感!不過拿腳趾頭想想也不會這么簡單,繼續完善
我們自己找茬
1、call支持多個參數,有可能一個也不沒有
2、考慮多參數時要把參數傳給擴展方法。
3、給上下文定義的函數要保持唯一不能是say
4、擴展完我們需要吧自定義函數刪除
接下來針對找茬問題一一解決
let Person = { name: "Tom", say() { console.log(this) console.log(`我叫${this.name}`) } } Person1 = { name: "Tom1" } //如果沒有參數 Person.say.call()
我們也要這樣
Function.prototype.MyCall = function(context) { // 如果沒有參數我們參考call的處理方式 context = context || window //context就是demo中的Person1 // 必須此時調用MyCall的函數是say方法,那么我們只需要在context上擴展一個say方法指向調用MyCall的say方法這樣this context.say = this //Mycall里邊的this就是我們虛擬的say方法 context.say() } Person.say.MyCall()
沒毛病!
繼續解決
// 找茬2:我們默認定義context.say = this fn如果已經被占用 嘎嘎 sb了。 不怕 搞定它 // say需要是一個唯一值 是不是突然想到es6的新類型 Symbol fn = Symbol() 不過我們裝逼不嫌事大 都說自己實現了 function mySymbol(obj) { // 不要問我為什么這么寫,我也不知道就感覺這樣nb let unique = (Math.random() + new Date().getTime()).toString(32).slice(0, 8) // 牛逼也要嚴謹 if (obj.hasOwnProperty(unique)) { return mySymbol(obj) //遞歸調用 } else { return unique } } //接下來我們一并把多參數和執行完刪除自定義方法刪除掉一塊搞定 Function.prototype.myCall1 = function(context) { // 如果沒有傳或傳的值為空對象 context指向window context = context || window let fn = mySymbol(context) context.fn = this //給context添加一個方法 指向this // 處理參數 去除第一個參數this 其它傳入fn函數 let arg = [...arguments].slice(1) //[...xxx]把類數組變成數組,arguments為啥不是數組自行搜索 slice返回一個新數組 context.fn(...arg) //執行fn delete context.fn //刪除方法 } let Person = { name: "Tom", say(age) { console.log(this) console.log(`我叫${this.name}我今年${age}`) } } Person1 = { name: "Tom1" } Person.say.call(Person1,18)//我叫Tom1我今年18
測試結果相當完美!
實現apply接下來apply就簡單多了,只有多參數時第二個參數是數組,就不一步步細說了。
Function.prototype.myApply = function(context) { // 如果沒有傳或傳的值為空對象 context指向window if (typeof context === "undefined" || context === null) { context = window } let fn = mySymbol(context) context.fn = this //給context添加一個方法 指向this // 處理參數 去除第一個參數this 其它傳入fn函數 let arg = [...arguments].slice(1) //[...xxx]把類數組變成數組,arguments為啥不是數組自行搜索 slice返回一個新數組 context.fn(arg) //執行fn delete context.fn //刪除方法 }實現bind
這個和call、apply區別還是很大的,容我去抽根煙回來收拾它
還是老套路先分析bind都能干些什么,有什么特點
1、函數調用,改變this 2、返回一個綁定this的函數 3、接收多個參數 4、支持柯里化形式傳參 fn(1)(2)
Function.prototype.bind = function(context) { //返回一個綁定this的函數,我們需要在此保存this let self = this // 可以支持柯里化傳參,保存參數 let arg = [...arguments].slice(1) // 返回一個函數 return function() { //同樣因為支持柯里化形式傳參我們需要再次獲取存儲參數 let newArg = [...arguments] console.log(newArg) // 返回函數綁定this,傳入兩次保存的參數 //考慮返回函數有返回值做了return return self.apply(context, arg.concat(newArg)) } } // 搞定測試 let fn = Person.say.bind(Person1) fn() fn(18)
是的,完美,實現了綁定this,返回函數,不立即執行,可以柯里化形式傳參。柯里化相關講解請移步:https://segmentfault.com/a/11...
簡版的實現就算完成了
歡迎吐槽or點贊!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101171.html
摘要:前言在阿里和騰訊工作了年,當了年的前端面試官,把期間我和我的同事常問的面試題和答案匯總在我的中。項目地址是我是小蝌蚪,騰訊高級前端工程師,跟著我一起每周攻克幾個前端技術難點。 前言 在阿里和騰訊工作了6年,當了3年的前端面試官,把期間我和我的同事常問的面試題和答案匯總在我 Github 的 Weekly-FE-Interview 中。希望對大家有所幫助。 如果你在bat面試的時候遇到了...
摘要:前言在阿里和騰訊工作了年,當了年的前端面試官,把期間我和我的同事常問的面試題和答案匯總在我的中。項目地址是我是小蝌蚪,騰訊高級前端工程師,跟著我一起每周攻克幾個前端技術難點。 前言 在阿里和騰訊工作了6年,當了3年的前端面試官,把期間我和我的同事常問的面試題和答案匯總在我 Github 的 Weekly-FE-Interview 中。希望對大家有所幫助。 如果你在bat面試的時候遇到了...
摘要:最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現,。后面以這道題為引線面試官可能會追問什么是執行上下文的判斷,的區別手寫一個函數實現斐波那契數列首先拷一個阮神在他教程里的一個寫法。 最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現bind,promise。手寫ajax,手寫一些算法。翻閱了很多書籍和博客。 這里做一個總結改進,算是對我后面大概為期一個月找...
JavaScript筆試部分 點擊關注本公眾號獲取文檔最新更新,并可以領取配套于本指南的 《前端面試手冊》 以及最標準的簡歷模板. 實現防抖函數(debounce) 防抖函數原理:在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。 那么與節流函數的區別直接看這個動畫實現即可。 showImg(https://segmentfault.com/img/remote/146000002...
閱讀 2142·2021-10-12 10:11
閱讀 843·2021-10-09 09:41
閱讀 3757·2021-09-09 11:37
閱讀 1933·2021-09-08 10:41
閱讀 2633·2019-08-30 12:58
閱讀 2369·2019-08-30 10:58
閱讀 1272·2019-08-26 13:40
閱讀 4097·2019-08-26 13:36