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

一文了解JavaScript中call/apply/bind的使用

 更新時(shí)間:2022年07月25日 08:53:46   作者:??橘皮?  
這篇文章主要介紹了一文了解JavaScript中call/apply/bind的使用,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下

前言

在JavaScript中,經(jīng)常會(huì)通過call / apply / bind 函數(shù)來改變this的指向,詳情可看一文帶你了解this指向,今天我們來研究下這三個(gè)函數(shù)的實(shí)現(xiàn)。

1. call

call()函數(shù)是什么?

call() 方法使用一個(gè)指定的 this 值和單獨(dú)給出的一個(gè)或多個(gè)參數(shù)來調(diào)用一個(gè)函數(shù)。也就是說call() 改變了this指向并執(zhí)行了函數(shù)。

1.1 語法

func.call(thisArg, arg1, arg2, ...)
// thisArg為在 func 函數(shù)運(yùn)行時(shí)使用的 this 值
// arg1, arg2等為指定的參數(shù)列表
// 其返回值為調(diào)用有指定 this 值和參數(shù)的函數(shù)的結(jié)果

1.2 流程圖

一般來說,我們要模擬實(shí)現(xiàn)call,可以分為以下幾個(gè)步驟:

  • 將函數(shù)設(shè)置為對(duì)象的屬性, 當(dāng)對(duì)象為null或undefined, 設(shè)為window對(duì)象
  • 取出函數(shù)執(zhí)行所需參數(shù),執(zhí)行該函數(shù)
  • 如果函數(shù)存在返回值,在返回后刪除該函數(shù)

以下就是call()方法實(shí)現(xiàn)的流程圖:

1.3 代碼實(shí)現(xiàn)

Function.prototype.call = function (thisArg, ...argsArray) {
  if (typeof this !== "function") {
    throw new TypeError(
      "Function.prototype.call was called on which is not a function"
    );
  }

  if (thisArg === undefined || thisArg === null) {
    thisArg = window;
  } else {
    thisArg = Object(thisArg);
  }

  // 將 func 放入 thisArg 內(nèi),這樣在調(diào)用 thisArg[func] 時(shí) this 自然就指向了 thisArg
  const func = Symbol("func");
  thisArg[func] = this;

  let result;

  if (argsArray.length) {
    result = thisArg[func](...argsArray);
  } else {
    result = thisArg[func]();
  }

  delete thisArg[func];

  return result;
};

2. apply

apply()函數(shù)是什么?

apply() 方法調(diào)用一個(gè)具有給定 this 值的函數(shù),以及以一個(gè)數(shù)組(或一個(gè)類數(shù)組對(duì)象)的形式提供的參數(shù)。同call()的功能,改變this指向的同時(shí)執(zhí)行了函數(shù)。

2.1 語法

func.apply(thisArg, [argsArray]);
// thisArg為在 func 函數(shù)運(yùn)行時(shí)使用的 this 值
// arg1, arg2等為指定的參數(shù)列表
// 其返回值為調(diào)用有指定 this 值和參數(shù)的函數(shù)的結(jié)果

2.2 流程圖

apply()方法實(shí)現(xiàn)的流程基本與call的實(shí)現(xiàn)流程沒有太多差異,只需要對(duì)函數(shù)參數(shù)數(shù)組進(jìn)行判斷展開即可。

以下是apply()函數(shù)的流程圖:

2.3 代碼實(shí)現(xiàn)

Function.prototype.apply = function (thisArg, argsArray) {
  if (typeof this !== "function") {
    throw new TypeError(
      "Function.prototype.apply was called on which is not a function"
    );
  }

  if (thisArg === undefined || thisArg === null) {
    thisArg = window;
  } else {
    thisArg = Object(thisArg);
  }

  // 將 func 放入 thisArg 內(nèi),這樣在調(diào)用 thisArg[func] 時(shí) this 自然就指向了 thisArg
  const func = Symbol("func");
  thisArg[func] = this;

  let result;

  if (argsArray && typeof argsArray === "object" && "length" in argsArray) {
    // 此處使用 Array.from 包裹讓其支持形如 { length: 1, 0: 1 } 這樣的類數(shù)組對(duì)象,直接對(duì) argsArray 展開將會(huì)執(zhí)行出錯(cuò)
    result = thisArg[func](...Array.from(argsArray));
  } else if (argsArray === undefined || argsArray === null) {
    result = thisArg[func]();
  } else {
    throw new TypeError("CreateListFromArrayLike called on non-object");
  }
  delete thisArg[func];
  return result;
};

3. bind

??bind() 函數(shù)是什么?

bind() 方法創(chuàng)建一個(gè)新的函數(shù),在 bind() 被調(diào)用時(shí),這個(gè)新函數(shù)的 this 被指定為 bind() 的第一個(gè)參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時(shí)使用。

3.1 語法

func.bind(thisArg[, arg1[, arg2[, ...]]])
// thisArg 為調(diào)用綁定函數(shù)時(shí)作為 this 參數(shù)傳遞給目標(biāo)函數(shù)的值, 如果使用 new 運(yùn)算符構(gòu)造綁定函數(shù),忽略該值
// arg1, arg2為當(dāng)目標(biāo)函數(shù)被調(diào)用時(shí),被預(yù)置入綁定函數(shù)的參數(shù)列表中的參數(shù)。
// 其返回值為一個(gè)原函數(shù)的拷貝,并擁有指定的 this 值和初始參數(shù)

3.2 流程圖

想要實(shí)現(xiàn)bind函數(shù),即需實(shí)現(xiàn)兩個(gè)特點(diǎn):一為返回一個(gè)函數(shù);二為可以傳入?yún)?shù)。

所以我們可從以下幾點(diǎn)入手:

  • 通過使用`call`或者`apply`實(shí)現(xiàn) `this`的指定;
  • 實(shí)現(xiàn)在`bind`的時(shí)候可以傳參,在執(zhí)行返回函數(shù)時(shí)傳參;
  • 判斷是否使用 `new`操作符來確定`this`指向。

話不多說,下面就是bind函數(shù)的流程圖:

3.3 代碼實(shí)現(xiàn)

Function.prototype.bind = function (thisArg, ...argsArray) {
  if (typeof this !== "function") {
    throw new TypeError(
      "Function.prototype.bind was called on which is not a function"
    );
  }
  if (thisArg === undefined || thisArg === null) {
    thisArg = window;
  } else {
    thisArg = Object(thisArg);
  }
  const func = this;
  const bound = function (...boundArgsArray) {
    let isNew = false;

    // 如果 func 不是構(gòu)造器,直接使用 instanceof 將出錯(cuò),所以需要用 try...catch 包裹
    try {
      isNew = this instanceof func;
    } catch (error) {}

    return func.apply(isNew ? this : thisArg, argsArray.concat(boundArgsArray));
  };

  const Empty = function () {};
  Empty.prototype = this.prototype;
  bound.prototype = new Empty();

  return bound;
};

4.全文總結(jié)

call、apply與bind有什么區(qū)別?

  • calll、apply 與 bind 都用于this綁定,但 call、apply 函數(shù)在改變this指向的同時(shí)還會(huì)執(zhí)行函數(shù);而 bind 函數(shù)在改變this后返回一個(gè)全新的綁定函數(shù)。
  • bind 屬于硬綁定,返回的綁定函數(shù)的this指向不能再通過 bind、apply 或 call 修改,即this被永久綁定;call 與 apply 只適用于當(dāng)前調(diào)用,一次調(diào)用后就結(jié)束。
  • call 和 apply 功能完全相同,但call 從第二個(gè)參數(shù)后的所有參數(shù)都是原函數(shù)的參數(shù);而 apply 只接受兩個(gè)參數(shù),第二個(gè)參數(shù)必須是數(shù)組,該數(shù)組包含著原函數(shù)的參數(shù)列表。

到此這篇關(guān)于一文了解JavaScript中call/apply/bind的使用的文章就介紹到這了,更多相關(guān)JavaScript call,apply,bind內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論