callメソッド、applyメソッド、bindメソッドは、関数やメソッドを指す thisを変更するために使用され、これらのメソッドを実装する際の違いを以下に簡単に説明します。
呼び出しメソッドの実装
関数が呼び出しメソッドを呼び出すとき、最初に渡されるパラメータは thisがどこを指しているかを示します。パラメータを渡さなかったり、undefined/nullを渡したりした場合、thisはウィンドウオブジェクトを指しており、それに続くパラメータは thisを変更する関数の実引数として使用されます。後続の引数は、thisのポイントを変更する関数の実引数として使用されます。関数実行のコンテキストでは、関数の thisは通常関数を呼び出すオブジェクトを指し、デフォルトではウィンドウを指します。
Function.prototype.mockcall=function(obj,...args){
他のブロガーがこのようなコードを書いているのを見ると、これは関数のプロトタイプに追加されるので、使う必要はないと思う。
もし他のアイデアがあれば、ぜひ試してみてほしい!
if(typeof this!=='function'){
throw new TypeError(`${this}.mockcall is not a function`)
}
//Symbolを使ってメソッド名を一意にし、オブジェクトの既存のプロパティと衝突しないようにする。
//objはオブジェクトではない可能性がある。
var fn=Symbol(),obj=Object(obj||window),result
//thisは呼び出しのメソッドを呼び出すことを意味し、objオブジェクトにメソッドを追加する。
obj[fn]=this
//objオブジェクトを通してメソッドを呼び出す。
result=obj[fn](...args)
//元のオブジェクトを復元する
delete obj[fn]
return result
}
問題:指定したいオブジェクトがフリーズしている場合、メソッドを追加することができません。
アプリケーションの実装
callメソッドと原理は同じですが、最初の2つのパラメータだけが有効で、2番目のパラメータは配列の形式でなければならず、thisが指すメソッドを変更するための実際のパラメータとして使用されるという違いがあります。
Function.prototype.mockapply=function(obj,arr){
if(arr&&!Array.isArray(arr)){
throw new TypeError('CreateListFromArrayLike called on non-object')
}
var fn=Symbol(),obj=Object(obj||window),result
//パラメータが渡されない場合、デフォルトは空の配列となる。
arr=arr||[]
obj[fn]=this
result=obj[fn](...arr)
delete obj[fn]
return result
}
バインドの実装
バインドの特徴
1 の場合は即座に実行されず、関数
2、new演算子の使用は、thisは、新しいオブジェクトを指しており、新しいオブジェクトのプロトタイプは、元の関数と戻り関数のプロトタイプを指しています。
3、bindを使用した後、callまたはapplyを使用しても、thisポインティングは変更されません。
4.bindを呼び出した後も、返された関数にパラメータを渡すことができます。
Function.prototype.mockbind=function(obj,...args){
var fn = this,
newFn=function(){},
bindF = function(...args1){
//実装の特徴 4
fn.call(this instanceof bindF?this:obj,...args,args1)
}
/*実装上の特徴2:新しいオブジェクトはbindFのインスタンスでなければならないので、fnを継承するためにはfnのプロトタイプが暗黙的な
bindFを使う代わりにプロトタイプチェインを使う.prototype=fn.prototypeは、メモリ共有を避けるために、bindF
プロトタイプはfnのプロトタイプに影響を与えるので、bindFをfnから継承するように設定する。
*/
//エラー: bindF.prototype=new fn()
//変更:null関数を使用してnull関数を継承し、null関数とfnプロトタイプが同じオブジェクトを指すようにした。
//fnを実行せずにfnを継承することに等しい。
newFn.prototype = fn.prototype
bindF.prototype = new newFn()
//実装の特徴1
return bindF
}
問題:mockbindを呼び出した後のcallやapply(例えばfun.bind(obj1).call(obj2) )は、thisが再び変更されることはありません。「なぜなら、mockbindによって返される関数はnew演算子が使われたときだけ修正されるからです。機能3は実装されましたが、問題はcallやapplyがbindFのインスタンスオブジェクトを渡した場合、mockbindの thisが変更されたままになってしまうことです。
bindF.prototype=newfn()としました。これは元の関数のプロトタイプに影響を与えずに継承を行う良い方法ですが、new演算子が継承中に元の関数を実行してしまうという問題があります。
1,
2.