【代碼片段】call、apply、bind

Lily 對(duì) LucyHello

const lily= {
  name: 'Lily',
  sayHello(helloWord, other){
    console.log(`${this.name} say ${helloWord} to ${other}`)
  }
}
lily.sayHello("hello", "Lucy")
// Lily say Hello to Lucy

那換做其他對(duì)象怎么復(fù)用sayHello方法呢

const jack = {
    name:'Jack'
}
lily.sayHello.call(jack, 'hello', 'Lilei')
// Jack say Hello to Lilei

lily.sayHello.apply(jack,[ 'hello', 'Lilei'])
// Jack say Hello to Lilei

let say2 = lily.sayHello.bind(jack,'hello')
say2('Lilei')
// Jack say Hello to Lilei
say2('David')
// Jack say Hello to David

下面實(shí)現(xiàn)call、 apply、bind的方法

Function.prototype.myCall = function(target,...args){
  target = target || window
//定義一個(gè)不會(huì)重復(fù)的key,作為目標(biāo)對(duì)象target的屬性key
  const funKey= Symbol()  
 //this即被調(diào)用的函數(shù)或?qū)ο螅瑢his變成目標(biāo)對(duì)象target屬性key的屬性值
  target[funKey] = this 
  const res = target[funKey](...args) 
  delete target[funKey] // 執(zhí)行完借用的函數(shù)后,刪除掉
  return res
}

 // 區(qū)別就是這里第二個(gè)參數(shù)直接就是個(gè)數(shù)組
Function.prototype.myApply = function(target,args){
  target = target || window
  const funKey= Symbol()
  target[funKey] = this
  const res = target[funKey](...args) 
  delete target[funKey]
  return res
}

// bind返回的是個(gè)函數(shù),需要執(zhí)行
Function.prototype.myBind = function (target,...outArgs) {
  target = target || {} 
  const funKey = Symbol()
  target[funKey] = this
  return function (...innerArgs) { // 返回一個(gè)函數(shù)
    const res = target[funKey](...outArgs, ...innerArgs) 
    //不能刪除,閉包函數(shù)(偏函數(shù))
    // delete target[funKey] 
    return res
  } 
}

從上面的myBind的實(shí)現(xiàn)看;bind涉及到閉包,下面說下閉包、偏函數(shù)、柯里化

轉(zhuǎn)自: JS閉包應(yīng)用-私有變量、柯里化、偏函數(shù)@ Peterer~王勇

什么是閉包?

function generate() {
  const a = 1;
  //注意需要return內(nèi)部函數(shù),才回形成閉包
  return function () {
    // a這個(gè)變量不在當(dāng)前作用域,于是它是一個(gè)自由變量。
    // 引用了自由變量的函數(shù)稱為閉包。
    console.log(a++);
  };
}

generate作為高階函數(shù)返回了一個(gè)新的函數(shù),該函數(shù)引用了外部作用域中的變量a,于是該函數(shù)稱為閉包函數(shù)。

  • 閉包就是:引用了自由變量的函數(shù)。
  • 自由變量:指在當(dāng)前作用域引用但既沒有定義在當(dāng)前作用域也未定義在全局作用域,而是定義在外層的局部作用域中的變量。

所以在此明確幾個(gè)關(guān)于閉包的要點(diǎn):

  • 閉包必然是定義在一個(gè)函數(shù)內(nèi)部的,因?yàn)榫植孔饔糜蛑淮嬗诤瘮?shù)內(nèi)。
  • 局部作用域的變量無法直接從外部訪問,只能通過作用域鏈訪問,所以閉包是訪問局部變量的橋梁。
  • 閉包造成的直接結(jié)果是自由變量不被垃圾回收,所以自由變量可以緩存一些信息。

閉包的典型應(yīng)用場(chǎng)景有兩個(gè):

  • 設(shè)置私有變量(基于局部變量的不可訪問性)
  • 柯里化和偏函數(shù)(基于自由變量的不回收性)

私有變量就是那些函數(shù)可以調(diào)用但是外部無法直接獲取的變量。比如下面這個(gè)場(chǎng)景:

function User() {
  // 這里的_password承擔(dān)著私有變量的作用
  let _password;
 
  return class User {
    constructor(username, password) {
      this.username = username;
      // 使用自由變量保存密碼
      _password = password;
    }
 
    login() {
      console.log(this.username, _password);
    }
  };
}
 
const user = new (User())("diana", "password");
 
user.login();
  • 我們希望隱藏用戶的密碼,只允許內(nèi)部訪問,此時(shí)就可以使用自由變量作為“私有變量”,返回一個(gè)閉包進(jìn)行訪問。
  • 局部變量的外部不可訪問性是關(guān)鍵,本質(zhì)上這一切都來自于JS使用的詞法作用域模型,變量只能從內(nèi)向外單向查找。

柯里化是一種操作技巧,在編程中指的是:將接受n個(gè)參數(shù)的單個(gè)函數(shù)轉(zhuǎn)換為接受單個(gè)參數(shù)的n個(gè)函數(shù)。比如下面這個(gè)場(chǎng)景:

function info(country, province, city) {
  console.log(country + "-" + province + "-" + city);
}

我們想要打印城市信息,對(duì)于某個(gè)省的城市我們需要重復(fù)的輸入country,province這兩個(gè)字段,此時(shí)我們可以對(duì)該函數(shù)進(jìn)行柯里化改造:

function info(country) {
  return function (province) {
    return function (city) {
      console.log(country + "-" + province + "-" + city);
    };
  };
}
const province = info("中國")("浙江省");
province("杭州市");
province("溫州市");
  • 我們將接受三個(gè)參數(shù)country,province,city的函數(shù)轉(zhuǎn)換為三個(gè)只接受單個(gè)參數(shù)的函數(shù),然后根據(jù)需要隨時(shí)生成一個(gè)已經(jīng)內(nèi)置”部分參數(shù)“的函數(shù)。
  • 這么做最大的好處是提高了代碼的復(fù)用性,我們可以提前緩存一些參數(shù),避免重復(fù)輸入。

偏函數(shù)也是一種操作技巧,在編程中指的是:將接受n個(gè)參數(shù)的單個(gè)函數(shù)任意固定a個(gè)參數(shù),返回接受剩余n-a個(gè)參數(shù)的函數(shù)。

偏函數(shù)和柯里化屬于一類操作,區(qū)別在于:

  • 柯里化強(qiáng)調(diào)函數(shù)只能接受“單參數(shù)”,有n個(gè)參數(shù)就要拆解為n個(gè)單參數(shù)函數(shù);
  • 偏函數(shù)更加“隨意”,將接受n個(gè)參數(shù)的函數(shù)一分為二,任意固定一個(gè)或多個(gè)參數(shù)。

上面的例子如果使用偏函數(shù):

function info(country) {
  return function (province, city) {
    console.log(country + "-" + province + "-" + city);
  };
}
 
info("中國")("浙江省", "杭州市");
info("中國")("浙江省", "溫州市");

柯里化和偏函數(shù)本質(zhì)沒什么區(qū)別,只是約束不同。能夠?qū)崿F(xiàn)這類操作的核心有兩點(diǎn):

  • 在于“自由變量”的不回收性,由于垃圾回收不去銷毀閉包中引用的自由變量,我們才能緩存部分參數(shù);
  • 在于JS使用靜態(tài)的詞法作用域,詞法作用域的劃分和查詢根據(jù)”代碼書寫“的位置來決定。

對(duì)this對(duì)象的理解

作者:CUGGZ
鏈接:https://juejin.cn/post/6941194115392634888
來源:稀土掘金

this 是執(zhí)行上下文中的一個(gè)屬性,它指向最后一次調(diào)用這個(gè)方法的對(duì)象。在實(shí)際開發(fā)中,this 的指向可以通過四種調(diào)用模式來判斷。

  • 第一種是函數(shù)調(diào)用模式,當(dāng)一個(gè)函數(shù)不是一個(gè)對(duì)象的屬性時(shí),直接作為函數(shù)來調(diào)用時(shí),this 指向全局對(duì)象。
  • 第二種是方法調(diào)用模式,如果一個(gè)函數(shù)作為一個(gè)對(duì)象的方法來調(diào)用時(shí),this 指向這個(gè)對(duì)象。
  • 第三種是構(gòu)造器調(diào)用模式,如果一個(gè)函數(shù)用 new 調(diào)用時(shí),函數(shù)執(zhí)行前會(huì)新創(chuàng)建一個(gè)對(duì)象,this 指向這個(gè)新創(chuàng)建的對(duì)象。
  • 第四種是 apply 、 call 和 bind 調(diào)用模式,這三個(gè)方法都可以顯示的指定調(diào)用函數(shù)的 this 指向。其中 apply 方法接收兩個(gè)參數(shù):一個(gè)是 this 綁定的對(duì)象,一個(gè)是參數(shù)數(shù)組。call 方法接收的參數(shù),第一個(gè)是 this 綁定的對(duì)象,后面的其余參數(shù)是傳入函數(shù)執(zhí)行的參數(shù)。也就是說,在使用 call() 方法時(shí),傳遞給函數(shù)的參數(shù)必須逐個(gè)列舉出來。bind 方法通過傳入一個(gè)對(duì)象,返回一個(gè) this 綁定了傳入對(duì)象的新函數(shù)。這個(gè)函數(shù)的 this 指向除了使用 new 時(shí)會(huì)被改變,其他情況下都不會(huì)改變。

這四種方式,使用構(gòu)造器調(diào)用模式的優(yōu)先級(jí)最高,然后是 apply、call 和 bind 調(diào)用模式,然后是方法調(diào)用模式,然后是函數(shù)調(diào)用模式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容