call、apply、bind の使用関数と手書きの実装

使用法

1.申し込む

apply2 つのパラメータを受け入れます。最初のパラメータはthisポインタで、2 番目のパラメータは関数によって受け入れられ、配列の形式で渡されるパラメータです。

this元の関数はポインタを変更した直後に実行されますが、このメソッドではthisポインタを一時的に 1 回だけ変更します。

文法:

func.apply(thisArg, [argsArray])

thisArg: 関数の実行時に this が指すオブジェクト、必須
argsArray: 関数の実行時に渡されるパラメーター、配列形式、オプション

例:

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '科比'}
fn.apply(obj, [1,2,3])
// 输出  科比 1 2 3

2.電話

apply同様に、ポインタthisを変更すると元の関数がすぐに実行されますが、このメソッドは一時的にthisポインタを 1 回変更するだけです。

違いは、apply で渡されるパラメータは配列形式である必要があるのに対し、call にはこの制限がないことです。

文法:

func.call(thisArg[, args1, args2, args3,....])

thisArg: 関数の実行時に this が指すオブジェクト、必須
args1 など: 関数の実行時に渡されるパラメーター、オプション

例:

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '科比'}
fn.call(obj, 1, 2, 3)
// 输出  科比  1 2 3

3.バインド

バインド メソッドは call に非常によく似ています。最初のパラメータもthisを指し、後で渡されるものはパラメータ リストです (ただし、このパラメータ リストは複数回渡すことができます)。

ポインタを変更した後this、すぐには実行されませんが、thisポインタを永続的に変更する関数が返されます。

文法:

func.bind(thisArg[, args1, args2, args3,....])
function fn (a, b, c, d) {
    console.log(this.name)
    console.log(a, b, c, d)
}
let obj = {name: '科比'}
let bindFn = fn.bind(obj, 1, 2, 3)
bindFn('bind') // 输出  科比  1 2 3 'bind'

 bindこの例から、新しい関数が返され、新しい関数の実行時にthisポイントされobjbind渡されたパラメータが新しい関数の呼び出し時に渡されたパラメータとマージされ、一緒に新しい関数に渡されることがわかります

手書きの実装:

上記の apply、call、bind の使用法から知ることができます。

apply、call、bind はすべて apply を指します。これにより this が変更される可能性があります
。Call は呼び出された関数を実行し、bind は新しい関数を返します。
apply の 2 番目のパラメータには配列が必要ですが、call と binding はデータ型を制限しません。残りのパラメータも一緒に関数に渡します。Bind は、新しい関数の呼び出し時に渡されたパラメータもマージして、それらを関数に渡します。新しい機能。
これらはすべて Function プロトタイプにバインドされています。
手書きで実装する方法を見てみましょう。なぜなら、それらはすべて Function プロトタイプにバインドされているからです。

1.申し込む

Function.prototype.apply = function (context, args) {
  // 不传默认是全局,window
  context = context || window
  // args不传时默认是空数组,防止下面用spread操作符时报错
  args = args ? args : []
  // 把this存到context.fn,这里的this是调用的函数
  context.fn = this
  // 执行调用的函数,this指向context,参数用spread操作符扩展
  const res = context.fn(...args)
  // 删除,不污染context
  delete context.fn
  // 返回res
  return res
}
function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '码上游'}
fn.apply(obj, [1,2,3])
// 输出  码上游  1 2 3

2.電話

call は apply と同じです。主な理由は、パラメーターが apply とは異なるためです。少し変更するだけです。

コードは以下のように表示されます。

Function.prototype.call = function (context, ...args) {
  // 不传默认是全局,window
  context = context || window
  // args不传时默认是空数组,防止下面用spread操作符时报错
  args = args ? args : []
  // 把this存到context.fn,这里的this是调用的函数
  context.fn = this
  // 执行调用的函数,this指向context,参数用spread操作符扩展
  const res = context.fn(...args)
  // 删除,不污染context
  delete context.fn
  // 返回res
  return res
}

これは主にcall関数の 2 番目のパラメータを取得するargsときに使用されspread操作符、残りのすべてのパラメータを args に取得でき、その他はすべて同じです。

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '科比'}
fn.call(obj, 1, 2, 3)
// 输出  科比  1 2 3

3.バインド

Bind は異なります。新しい関数を返します。この新しい関数は、演算子を使用して呼び出したり、コンストラクターとして使用したりできるnewため、ここで区別する必要があります。

Function.prototype.bind = function (context, ...args) {
  // 不传默认是全局,window
  context = context || window
  // 把this存到fn,这里的this是调用的函数
  let fn = this
  return function newFn (...fnArgs) {
    let res
    // 要考虑新函数是不是会当作构造函数
    if (this instanceof newFn) {
      // 如果是构造函数则调用new 并且合并参数args,fnArgs
      res = new fn(...args, ...fnArgs)
    } else {
      // 当作普通函数调用 也可以用上面定义的_call
      res = fn.call(context, ...args, ...fnArgs)
    }
    return res
  }
}

確認する

function fn (a, b, c, d) {
    console.log(this.name)
    console.log(a, b, c, d)
}
let obj = {name: '科比'}
let bindFn = fn.bind(obj, 1, 2, 3)
bindFn('bind') // 输出  科比  1 2 3 'bind'
 
let bindFn = fn.bind(obj, 1, 2, 3)
let instance = new bindFn()
instance.constructor === fn // true

おすすめ

転載: blog.csdn.net/LoveHaixin/article/details/133038002