この記事では、js でネイティブに呼び出し、適用、バインドを実装する方法を説明します。必要な場合は参考にしてください。
これが指摘する問題に関連しているため、call、apply、bind の使用法は常套句であると言えます。この記事の主な目的は、JS ネイティブ メソッドを使用して 3 つのメソッドを実装し、原理を理解し、関連する知識ポイントをよりよく理解することです。 github アドレスのネイティブ実装 call、apply、bind
簡単な紹介: 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 も関数メソッドであり、その機能は 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でネイティブに呼び出し、適用、バインドを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。