ホームページ  >  記事  >  ウェブフロントエンド  >  JSでネイティブに呼び出し、適用、バインドを実装する方法

JSでネイティブに呼び出し、適用、バインドを実装する方法

不言
不言オリジナル
2018-07-23 11:26:582099ブラウズ

この記事では、js でネイティブに呼び出し、適用、バインドを実装する方法を説明します。必要な場合は参考にしてください。

これが指摘する問題に関連しているため、call、apply、bind の使用法は常套句であると言えます。この記事の主な目的は、JS ネイティブ メソッドを使用して 3 つのメソッドを実装し、原理を理解し、関連する知識ポイントをよりよく理解することです。 github アドレスのネイティブ実装 call、apply、bind

call と apply

簡単な紹介: call メソッドと apply メソッドは両方とも、指定された this 値と対応するパラメーターを使用して関数またはメソッドを呼び出します。違いは、call は複数のパラメータを渡すのに対し、apply は配列を渡すことです。
例:

var obj = {
  name: 'linxin'
}

function func(age, sex) {
  console.log(this.name,age,sex);
}

func.call(obj,12,'女');         // linxin 12 女
func.apply(obj, [18, '女']);        //linxin 18 女

シミュレーションの実装

アイデア: JavaScript の this ポインターは、関数はオブジェクトのメソッドとして呼び出すこともでき、その場合、これは上位オブジェクトを参照します。誰が電話しても、これは私たちが通常言うことです。したがって、実装方法は、そのようなメソッドを受信オブジェクトに追加してから、このメソッドを実行することです。オブジェクトを永続的に保つために、オブジェクトは実行後に削除されます。とても簡単ですね^-^。
初体験:

Function.prototype.newCall = function(context) {
  context.fn = this;  // 通过this获取call的函数
  context.fn();
  delete context.fn;
}
let foo = {
  value: 1
}
function bar() {
  console.log(this.value);
}
bar.newCall (foo); // 1

これで基本バージョンの実装は完了しましたが、渡すパラメータがある場合はどうすればよいでしょうか?
渡されるパラメータの数は不確実なので、比較的単純な Arguments オブジェクトから取得できるため、最適化できます。問題は、パラメータが不確実であることです。実行したい関数にパラメータを渡すにはどうすればよいでしょうか。 ここには 2 つのオプションがあります。1 つは eval スプライシングを使用するもので、もう 1 つは es6 を使用するものです。
体験アップグレード (評価版):

Function.prototype.newCall = function(context) {
  context.fn = this;
  var args = [];
  for(var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']');
  }
  eval('context.fn(' + args +')');
  delete context.fn;
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

体験アップグレード (ES6 バージョン):

Function.prototype.newCall = function(context) {
  context.fn = this;  
  context.fn(...Array.from(arguments).slice(1));
  delete context.fn;
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

ES6 メソッドは引数を使用せずに実装できます
ES6 バージョンを再度アップグレードします:

Function.prototype.newCall = function(context, ...parameter) {
  context.fn = this;  
  context.fn(...parameter);
  delete context.fn;
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

この方法があります基本的に通話機能を実装しましたが、まだいくつかの隠れた危険性と違いがあります。
オブジェクト自体に fn メソッドがある場合、大きな問題が発生します。
呼び出しによって渡されたオブジェクトが null またはその他の型の場合、関数はエラーを報告します。
究極のエクスペリエンス:

Function.prototype.newCall = function(context, ...parameter) {
  if (typeof context === 'object') {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context[fn] = this
  context[fn](...parameter);
  delete context[fn]
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

呼び出しを実装した後、apply も同じ考えになります。
apply 実装:

Function.prototype.newApply = function(context, parameter) {
  if (typeof context === 'object') {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context[fn] = this
  context[fn](parameter);
  delete context[fn]
}

bind

bind も関数メソッドであり、その機能は this の実行を変更することであり、複数のパラメーターを渡すこともできます。 call や apply とは異なり、bind メソッドはすぐには実行されませんが、このメソッドが指すコンテキストを変更する関数を返します。元の関数は変更されていません。また、関数自体がこのオブジェクトにバインドされた関数である場合、apply と call は期待どおりに実行されません。
初体験:

Function.prototype.bind = function (context) {
  var me = this
  return function () { // bind之后得到的函数
    return me.call(context)  // 执行是改变this执行
  }
}

追加されたパラメータ:

Function.prototype.bind = function (context,...innerArgs) {
  var me = this
  return function (...finnalyArgs) {
    return me.call(context,...innerArgs,...finnalyArgs)
  }
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
let personSayHi = sayHi.bind(person, 25)
personSayHi('男')

関連する推奨事項:

js (名前空間) のモジュラー分析

JS 継承 (プロトタイプ チェーン、コンストラクター、組み合わせ、プロトタイプ、寄生、寄生の組み合わせ、クラス拡張)

以上がJSでネイティブに呼び出し、適用、バインドを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。