JS面試中你不知道的call apply bind方法及使用場(chǎng)景詳解
面試
面試官 :說(shuō)一下 call apply bind 的三者區(qū)別吧?
我:啊.....這。
三者區(qū)別
call
我們先來(lái)看看 call call 函數(shù)接收兩個(gè)參數(shù)
@params1 需要指向this
@params2 需要攜帶的參數(shù)
就拿這段代碼 來(lái)說(shuō) 我調(diào)用 foo 函數(shù) 的時(shí)候 想去 執(zhí)行obj 中的 eat函數(shù) 怎么辦?
默認(rèn) 我的 foo 里面什么頁(yè)面有 怎么可能會(huì)打印 吃飯呢?this默認(rèn)指向 window ,window 對(duì)象中 沒(méi)有 eat 方法不應(yīng)該 報(bào)錯(cuò) not defind 嗎?
let obj = {
eat: function (args) {
console.log("吃飯", args);
}
}
function foo(...args) {
this.eat(args)
}
你可以這樣 , 此時(shí)調(diào)用的時(shí)候 foo 的函數(shù) this 就指向了 obj 但是只是這一次調(diào)用哦 ,下次 this 是指向 window 的
console.log(foo.call(obj, 123, 456)); / / 吃飯 [ 123, 456 ]
調(diào)用結(jié)果 : 傳入 this 和 參數(shù) 立即執(zhí)行函數(shù)
apply.
@params1 需要指向this
@params2 需要攜帶的參數(shù) 傳入的參數(shù)數(shù)據(jù)類(lèi)型為 Array
let obj = {
eat: function (args) {
console.log("吃飯", args);
}
}
function foo(...args) {
this.eat(args)
}
console.log(foo.apply(obj, [1, 2, 3])); // 吃飯 [1,2,3 ]
調(diào)用結(jié)果 : 傳入 this 和 參數(shù),立即執(zhí)行
bind
@params1 需要指向this
@params2 需要攜帶的參數(shù)
let obj = {
eat: function (args) {
console.log("吃飯", args);
}
}
function foo(...args) {
this.eat(args)
}
console.log(foo.bind(obj, 1, 2, 3)()); //吃飯 [ 1, 2, 3 ]
調(diào)用結(jié)果 : 傳入 this 和 參數(shù) 返回一個(gè) 新的函數(shù),不會(huì)立即執(zhí)行
總結(jié)
call 函數(shù) 傳入綁定 this的對(duì)象 ,攜第二個(gè)參數(shù)以 參數(shù)列表形式傳入 并會(huì)立即執(zhí)行
apply 函數(shù) 傳入綁定 this的對(duì)象 第二個(gè)參數(shù)以 數(shù)組的形式 傳入 并會(huì)立即執(zhí)行
bind 函數(shù) 傳入綁定 this的對(duì)象 第二個(gè)參數(shù)以 數(shù)組或參數(shù)列表的形式傳入 不會(huì)立即執(zhí)行函數(shù)會(huì)返回一個(gè)新的函數(shù) 自由調(diào)用
應(yīng)用場(chǎng)景
利用call 實(shí)現(xiàn) 構(gòu)造函數(shù)原型繼承
function Person(name, age, friends) {
this.friends = friends
this.name = name
this.age = age
}
Person.prototype.eat = function () {
console.log(`${this.name}在吃飯`);
}
Person.prototype.running = function () {
console.log(`${this.name}去跑步了`);
}
function Student(study, name, age, friedns) {
Person.call(this, name, age, friedns)
this.study = study
}
function Teacher(plaseLoveStudent) {
this.plaseLoveStudent = plaseLoveStudent
}
//繼承 person
Student.prototype = new Person()
const stu = new Student('語(yǔ)文', "張三", 18, ['王安石'])
const stu2 = new Student('數(shù)學(xué)', "李四", 18, ['哈利波特'])
const tec = new Teacher("王安怡")
console.log(stu === stu2);
console.log(stu);
console.log(stu.friends);
console.log(stu2.friends);
簡(jiǎn)單實(shí)現(xiàn)
call
實(shí)現(xiàn)思路 :
1:在Function 原型身上添加一個(gè)方法。
2:mycall 接受 兩個(gè)參數(shù) 一個(gè)是綁定的 this,還有就是 參數(shù)列表
3:保存調(diào)用者,其實(shí)這里更嚴(yán)謹(jǐn)一點(diǎn)還需要判斷調(diào)用者的 類(lèi)型
4:判斷傳入的thisArgs 是不是 undefined 或者 null 如果是 則 this指向 window 否則將 綁定的 this封裝成 一個(gè)對(duì)象
5:然后將 函數(shù)本身保存在 上面封裝好的對(duì)象中
6:調(diào)用并傳入args
7:完成實(shí)現(xiàn) this指向的改變
Function.prototype.mycall = function (thisArgs, ...args) {
/**
*
* 保存this(當(dāng)前調(diào)用者)
*
*/
const newFunc = this
// 在當(dāng)前調(diào)用者 this身上 保存 調(diào)用者
thisArgs = (thisArgs !== undefined && thisArgs !== null) ? Object(thisArgs) : window
thisArgs.func = newFunc
thisArgs.func(...args)
}
apply
apply 就不說(shuō)了 實(shí)現(xiàn)思路是一樣的 只不過(guò)傳入的參數(shù)不一樣做一個(gè)判斷就行了
Function.prototype.myapply = function (thisArgs, argArray) {
if (!(argArray instanceof Array)) {
throw '參數(shù)類(lèi)型限定為 Array'
}
else {
const func = this
thisArgs = (thisArgs !== undefined && thisArgs !== null) ? Object(thisArgs) : window
thisArgs.fn = func
thisArgs.fn(argArray)
}
}
bind
bind 跟 apply call 有一些區(qū)別
bind 會(huì)返回一個(gè)新的函數(shù) , 所以我們?cè)趦?nèi)部需要自己定義一個(gè) 函數(shù) 給返回出去, 并且,可能出現(xiàn) 返回新函數(shù)調(diào)用時(shí) 繼續(xù)傳入?yún)?shù) 所以我們需要將參數(shù)合并
Function.prototype.mybind = function (thisArgs, ...argArray) {
const oldFunc = this
console.log(this);
thisArgs = (thisArgs !== undefined && thisArgs !== null) ? Object(thisArgs) : window
function proxyFn(...args) {
thisArgs.func = oldFunc
const funcCallResult = thisArgs.func([...argArray, ...args]) // 合并兩次的 參數(shù)
delete thisArgs.func
return funcCallResult
}
return proxyFn
}
謝謝,到此就完成了簡(jiǎn)單版的 call apply bind 的實(shí)現(xiàn),更多關(guān)于JS call apply bind方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS輕量級(jí)函數(shù)式編程實(shí)現(xiàn)XDM二
這篇文章主要為大家介紹了JS函數(shù)式編程實(shí)現(xiàn)XDM示例詳解第2/3篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
JavaScript前端實(shí)用的工具函數(shù)封裝
這篇文章主要為大家介紹了JavaScript前端實(shí)用的一些工具函數(shù)的封裝,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
微信小程序獲取循環(huán)元素id以及wx.login登錄操作
這篇文章主要介紹了微信小程序獲取循環(huán)元素id以及wx.login登錄操作的相關(guān)資料,這里提供實(shí)例幫助大家實(shí)現(xiàn)該功能,需要的朋友可以參考下2017-08-08

