欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript實(shí)現(xiàn)手寫call/apply/bind的示例代碼

 更新時(shí)間:2023年02月08日 11:31:01   作者:mick  
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)手寫call/apply/bind的方法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)JavaScript有一定的幫助,需要的可以參考一下

還記得之前面試得物的時(shí)候,上來就是一道手寫bind,當(dāng)時(shí)咱也不知道啥情況,也沒準(zhǔn)備什么手寫的題目,就這樣輕輕松松的掛了

現(xiàn)在前端行業(yè)那么的卷,面試的時(shí)候讓你手寫的個(gè)什么東西是非常常見的。下面是我總結(jié)的3道手寫題。希望對你有幫助。

call

call的作用是啥

我們首先看一個(gè)案例

let foo = {
  value: 1
}

function bar() {
  console.log(this.value)
}

bar.call(foo) //1

可以總結(jié)兩個(gè)點(diǎn):

  • call改變了bar的this指向,指向了foo
  • bar被執(zhí)行了 那我們是不是可以理解為是這樣的情況呢
let foo = {
  value: 1,
  bar: function() {
    console.log(this.value)
  }
}
foo.bar()

我們可以看到這個(gè)時(shí)候this就指向了foo,但是多了一個(gè)屬性,那再把這個(gè)屬性刪掉就是咯。所以我們的思路可以是這樣的:

  • 將函數(shù)設(shè)置成foo的屬性
  • 執(zhí)行這個(gè)函數(shù)
  • 刪除這個(gè)函數(shù) 暫時(shí)可以先寫成這樣
Function.prototype.myCall = function (context) {
  context.fn = this
  context.fn()
  delete context.fn
}

現(xiàn)在我們再回到最初的案例,然后加上參數(shù)

let foo = {
  value: 1
}

function bar(name, age) {
  console.log(this.value)
  console.log(name)
  console.log(age)
}

bar.call(foo, "mick", 18)
// 1
// mick
// 18

那我們就可以把call去除第一個(gè)參數(shù),然后剩下的參數(shù)在執(zhí)行的時(shí)候添加進(jìn)去就好了

Function.prototype.myCall = function (context) {
  context.fn = this
  const args = [...arguments].slice(1)
  context.fn(...args)
  delete context.fn
}

我們修改下案例

var value = 1
function bar() {
  console.log(this.value)
}

bar.call(null) // 1

當(dāng)綁定的this指向?yàn)閚ull的時(shí)候,則認(rèn)識(shí)指向了window

let foo = {
  value: 1
}

function bar(name, age) {
  return {
    value: this.value,
    name,
    age
  }
}

console.log(bar.call(foo, "mick", 18))
// { value: 1, name: 'mick', age: 18 }

如果函數(shù)有返回值,我們實(shí)現(xiàn)的call不能僅僅是執(zhí)行了,也要有返回值。

Function.prototype.myCall = function (context) {
  context = context || window
  context.fn = this
  const args = [...arguments].slice(1)
  const res = context.fn(...args)
  delete context.fn
  return res
}

這樣就實(shí)現(xiàn)了一個(gè)call

總結(jié)

  • 將函數(shù)設(shè)置成要指向的那個(gè)this的屬性
  • 執(zhí)行這個(gè)函數(shù)
  • 刪除這個(gè)屬性
  • 考慮參數(shù)問題
  • 考慮this為null的情況
  • 考慮下返回值

apply

apply和call差不多,只是入?yún)⒉灰粯?,apply的參數(shù)是數(shù)組

Function.prototype.myApply = function (context, arr) {
  context = context || window
  context.fn = this
  var res
  if (!arr) {
    res = context.fn()
  } else {
    res = context.fn(...arr)
  }
  delete context.fn
  return res
}

bind

MDN上解釋的bind為:bind()  方法創(chuàng)建一個(gè)新的函數(shù),在 bind() 被調(diào)用時(shí),這個(gè)新函數(shù)的 this 被指定為 bind() 的第一個(gè)參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時(shí)使用。 我們可以得出兩個(gè)點(diǎn):

  • 返回一個(gè)新的函數(shù)
  • 可以傳入?yún)?shù)

先看下案例:

var foo = {
  value: 1
}

function bar(name, age) {
  console.log(this.value)
  console.log(name)
  console.log(age)
}

var bindFoo = bar.bind(foo, "mick")

bindFoo(18)
// 1
// mick
// 18

可以看到 bind的參數(shù)和返回的bindFoo的參數(shù)是合并的,而改變this可以利用apply來實(shí)現(xiàn)

Function.prototype.myBind = function (context) {
  const self = this
  const args = [...arguments].slice(1)
  return function () {
    const bindArgs = [...arguments].slice()
    return self.apply(context, args.concat(bindArgs))
  }
}

然而bind還有一個(gè)特點(diǎn)。在MDN上這樣說到:綁定函數(shù)自動(dòng)適應(yīng)于使用new操作符去構(gòu)造一個(gè)由目標(biāo)函數(shù)創(chuàng)建的新實(shí)例。當(dāng)一個(gè)綁定函數(shù)是用來構(gòu)建一個(gè)值的,原來提供的 this 就會(huì)被忽略。不過提供的參數(shù)列表仍然會(huì)插入到構(gòu)造函數(shù)調(diào)用時(shí)的參數(shù)列表之前。

所以當(dāng)執(zhí)行bind被返回的那個(gè)函數(shù)被當(dāng)做構(gòu)造函數(shù)的時(shí)候,bind綁定的this值就會(huì)失效。 我們看下案例:

var value = 2

var foo = {
  value: 1
}

function bar(name, age) {
  this.hobby = "studying"
  console.log(this.value)
  console.log(name)
  console.log(age)
}

bar.prototype.friend = "randy"

var bindFoo = bar.bind(foo, "mick")

var obj = new bindFoo(18)
// undefined
// mick
// 18

console.log(obj.hobby)
console.log(obj.friend)
// studying
// randy

可以看出this失效了,所以我們要完善一下

Function.prototype.myBind = function (context) {
  const self = this
  const args = [...arguments].slice(1)
  var fBound = function () {
    const bindArgs = [...arguments].slice()
    // 用apply 實(shí)現(xiàn)this的綁定
    return self.apply(
      this instanceof fBound ? this : context,
      args.concat(bindArgs)
    )
  }

  fBound.prototype = this.prototype

  return fBound
}

首先加了this instanceof fBound 這個(gè)主要是為了判斷fBound是不是被當(dāng)做構(gòu)造函數(shù)使用的,如果是,那么將綁定函數(shù)的this指向該實(shí)例。fBound.prototype = this.prototype修改fBound的prototype是為了綁定函數(shù)的prototype,實(shí)例就可以繼承綁定函數(shù)原型中的值了。這也是為什么new bindFoo的實(shí)例能夠訪問bar原型的屬性。

優(yōu)化

fBound.prototype = this.prototype,當(dāng)我直接修改fBound的prototype的時(shí)候,也會(huì)直接修改綁定函數(shù)bar的prototype。這時(shí)候我們就需要一個(gè)空函數(shù)來中轉(zhuǎn):

Function.prototype.myBind = function (context) {
  const self = this
  const args = [...arguments].slice(1)

  var fNOP = function () {}
  var fBound = function () {
    const bindArgs = [...arguments].slice()
    // 用apply 實(shí)現(xiàn)this的綁定
    return self.apply(
      this instanceof fNOP ? this : context,
      args.concat(bindArgs)
    )
  }

  fNOP.prototype = this.prototype
  fBound.prototype = new fNOP()

  return fBound
}

總結(jié)

  • 執(zhí)行bind返回一個(gè)新的函數(shù)
  • bind的參數(shù)和返回新的函數(shù)的參數(shù)會(huì)拼接,bind的參數(shù)優(yōu)先級更高
  • 如果返回的函數(shù)當(dāng)做構(gòu)造函數(shù)使用的時(shí)候,this會(huì)失效
  • 修改原型的值需要一個(gè)中轉(zhuǎn)優(yōu)化

以上就是JavaScript實(shí)現(xiàn)手寫call/apply/bind的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于JavaScript call apply bind的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaScript禁止頁面回退的方法步驟

    JavaScript禁止頁面回退的方法步驟

    這篇文章主要為大家介紹了JavaScript禁止頁面回退的方法步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • JS實(shí)現(xiàn)定時(shí)頁面彈出類似QQ新聞的提示框

    JS實(shí)現(xiàn)定時(shí)頁面彈出類似QQ新聞的提示框

    類似QQ新聞的提示框要求頁面每隔半小時(shí)彈出一次提示消息,下面有個(gè)不錯(cuò)的實(shí)現(xiàn)方法,感興趣的朋友可以參考下
    2013-11-11
  • js實(shí)現(xiàn)彈窗居中的簡單實(shí)例

    js實(shí)現(xiàn)彈窗居中的簡單實(shí)例

    下面小編就為大家?guī)硪黄猨s實(shí)現(xiàn)彈窗居中的簡單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-10-10
  • uniapp內(nèi)置組件scroll-view案例詳解(完整代碼)

    uniapp內(nèi)置組件scroll-view案例詳解(完整代碼)

    這篇文章主要介紹了uniapp內(nèi)置組件scroll-view案例詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • underscore之function_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    underscore之function_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    因?yàn)閡nderscore本來就是為了充分發(fā)揮JavaScript的函數(shù)式編程特性,所以也提供了大量JavaScript本身沒有的高階函數(shù)。本文重點(diǎn)給大家介紹underscore之function知識(shí),感興趣的的朋友一起學(xué)習(xí)吧
    2017-07-07
  • 原生JS面向?qū)ο髮?shí)現(xiàn)打字小游戲

    原生JS面向?qū)ο髮?shí)現(xiàn)打字小游戲

    這篇文章主要為大家詳細(xì)介紹了原生JS面向?qū)ο髮?shí)現(xiàn)打字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • js中更短的 Array 類型轉(zhuǎn)換

    js中更短的 Array 類型轉(zhuǎn)換

    代碼永遠(yuǎn)都是那么好玩,而 Trick 不斷。那天張克軍在 twitter 上說還有比 [].slice.call() 更短的 Array 轉(zhuǎn)換么
    2011-10-10
  • Javascript中判斷對象是否具有屬性的5種方法分享

    Javascript中判斷對象是否具有屬性的5種方法分享

    這篇文章主要介紹了Javascript中判斷對象是否具有屬性的5種方法分享,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08
  • JavaScript判斷是否手機(jī)瀏覽器的五種方法

    JavaScript判斷是否手機(jī)瀏覽器的五種方法

    現(xiàn)在手機(jī)網(wǎng)站已經(jīng)很普及了,有時(shí)候前端網(wǎng)頁需要判斷,用戶使用的是手機(jī)瀏覽器還是電腦瀏覽器。這篇文章整理了JavaScript判斷是否手機(jī)瀏覽器的五種方法,通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值
    2022-11-11
  • JavaScript實(shí)現(xiàn)全選與反選功能

    JavaScript實(shí)現(xiàn)全選與反選功能

    這篇文章主要為大家詳細(xì)介紹了如何分別使用Vue和JavaScript實(shí)現(xiàn)全選與反選功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04

最新評論