簡単なシミュレーションでJavascriptのcall、appy、bind方法を実現します.
6222 ワード
目次ガイド 暗黙的な損失 ハードバインド 実装および原理解析 全体実装(純版/コメントなし) は最後に書いてあります.
引子優待券サイトwww.cs.3 cn
「あなたが知らないJavaScript--上巻」の中でthisに関する紹介と深い章節を読み終わった後、thisに対する指向についてこの文章で簡単にまとめました.続いて、thisに関する知識を利用して、javascriptでよく使われているcall、appy、bindの方法をシミュレーションして実現してもいいですか?
そこで本文があって、雑談は多く全文を言わないで始まります!
陰でなくします
アナログ実装では暗黙的に使われることがありますので、ここで紹介します.
暗黙的な損失とは、暗黙的に結合された関数がバインディングされたオブジェクトをなくし、最終的にデフォルトのバインディングに適用されるという共通のthisバインディング問題である.本来は暗黙的バインディング(
よくある暗黙的な損失状況1:引用伝達
さらに全体的な実現の鍵となる原理が得られます.いくら値が伝達されても、最終的な呼び出し方法でthisの方向が決定されます.
ハードバインディング
直観的な説明ハードバインディングとは、一度関数を明示的に指定したら、thisが終わったら、その後どうやって呼び出しても、そのthisの方向はもう変えられないということです.
ハードバインディングの実現は陰的な損失による問題を解決しました.bind関数の実現利用はハードバインディングの原理です.
アナログ実現call
私はただ前端の白を勉強しています.間違っているところがあります.よろしくお願いします.
もしあなたにインスピレーションや助けがあると感じたら、メッセージや関心をお願いします.ありがとうございます.
引子優待券サイトwww.cs.3 cn
「あなたが知らないJavaScript--上巻」の中でthisに関する紹介と深い章節を読み終わった後、thisに対する指向についてこの文章で簡単にまとめました.続いて、thisに関する知識を利用して、javascriptでよく使われているcall、appy、bindの方法をシミュレーションして実現してもいいですか?
そこで本文があって、雑談は多く全文を言わないで始まります!
陰でなくします
アナログ実装では暗黙的に使われることがありますので、ここで紹介します.
暗黙的な損失とは、暗黙的に結合された関数がバインディングされたオブジェクトをなくし、最終的にデフォルトのバインディングに適用されるという共通のthisバインディング問題である.本来は暗黙的バインディング(
obj.xxx
thisはObjを指す)の場合、最終的にデフォルトバインディング(thisはグローバルオブジェクトを指す)を適用する.よくある暗黙的な損失状況1:引用伝達
var a = 'window'
function foo() {
console.log(this.a)
}
var obj = {
a: 'obj',
foo: foo
}
obj.foo() // 'obj' this => obj
var lose = obj.foo
lose() // 'window' this => window
一般的な暗黙的な損失の場合2:コールバック関数として伝えられます.var a = 'window'
function foo() {
console.log(this.a)
}
var obj = {
a: 'obj',
foo: foo
}
function lose(callback) {
callback()
}
lose(obj.foo) // 'window' this => window
// ================ ===============
var t = 'window'
function bar() {
console.log(this.t)
}
setTimeout(bar, 1000) // 'window'
これについて私がまとめた考え(正しいかどうかは分かりません):明示的なバインディングを排除した後、どのように値伝達をしても、最後には何の修飾もない呼び出しがある限り、デフォルトのバインディングに適用されます.さらに全体的な実現の鍵となる原理が得られます.いくら値が伝達されても、最終的な呼び出し方法でthisの方向が決定されます.
ハードバインディング
直観的な説明ハードバインディングとは、一度関数を明示的に指定したら、thisが終わったら、その後どうやって呼び出しても、そのthisの方向はもう変えられないということです.
ハードバインディングの実現は陰的な損失による問題を解決しました.bind関数の実現利用はハードバインディングの原理です.
//
var a = 'window'
function foo() {
console.log(this.a)
}
var obj = {
a: 'obj',
foo: foo
}
function lose(callback) {
callback()
}
lose(obj.foo) // 'window'
var fixTheProblem = obj.foo.bind(obj)
lose(fixTheProblem) // 'obj'
実現及び原理分析アナログ実現call
// call
Function.prototype._call = function ($this, ...parms) { // ...parms rest ,
/*
this _call this
** ** => $this(context)
*/
$this['caller'] = this
//$this['caller'](...parms)
//
$this.caller(...parms) // ...parms spread , caller
/*
,
1. $this.caller this
2. $this.caller ,
3. this $this
*/
delete $this['caller'] // ,
}
アナログ実装// apply ** _call , / **
Function.prototype._apply = function ($this, parmsArr) { // apply
$this['caller'] = this
$this['caller'](...parmsArr) // ...parmsArr spread , caller
delete $this['caller']
}
からにはコールとコールapplyの前の類似度(結合度)がこんなに高いなら、私達はさらにそれら(同じコード)を引き離すことができます.function interface4CallAndApply(caller, $this, parmsOrParmArr) {
$this['caller'] = caller
$this['caller'](...parmsOrParmArr)
delete $this['caller']
}
Function.prototype._call = function ($this, ...parms) {
var funcCaller = this
interface4CallAndApply(funcCaller, $this, parms)
}
Function.prototype._apply = function ($this, parmsArr) {
var funcCaller = this
interface4CallAndApply(funcCaller, $this, parmsArr)
}
一つはよく展示できると思います.コールとコールapply実現原理の例var myName = 'window'
var obj = {
myName: 'Fitz',
sayName() {
console.log(this.myName)
}
}
var foo = obj.sayName
var bar = {
myName: 'bar',
foo
}
bar.foo()
アナログ実現ビッド// bind
Function.prototype._bind = function ($this, ...parms) {
$bindCaller = this // _bind :
// bind :
return function () { // rest arguments
return $bindCaller._apply($this, parms)
}
}
ハードバインディングの原理を示すことができる例function hardBind(fn) {
var caller = this
var parms = [].slice.call(arguments, 1)
return function bound() {
parms = [...parms, ...arguments]
fn.apply(caller, parms) // apply
}
}
var myName = 'window'
function foo() {
console.log(this.myName)
}
var obj = {
myName: 'obj',
foo: foo,
hardBind: hardBind
}
//
foo() // 'window'
obj.foo() // 'obj'
var hb = hardBind(foo)
// this
hb() // 'window'
obj.hb = hb // obj
obj.hb() // 'window'
//
var hb2 = obj.hardBind(foo)
hb2() // 'obj' // this window
全体的な実現(純版/コメントなし)function interface4CallAndApply(caller, $this, parmsOrParmArr) {
$this['caller'] = caller
$this['caller'](...parmsOrParmArr)
delete $this['caller']
}
Function.prototype._call = function ($this, ...parms) {
var funcCaller = this
interface4CallAndApply(funcCaller, $this, parms)
}
Function.prototype._apply = function ($this, parmsArr) {
var funcCaller = this
interface4CallAndApply(funcCaller, $this, parmsArr)
}
Function.prototype._bind = function ($this, ...parms) {
$bindCaller = this
return function () {
return $bindCaller._apply($this, parms)
}
}
// ============ ===============
var foo = {
name: 'foo',
sayHello: function (a, b) {
console.log(`hello, get the parms => ${a} and ${b}`)
}
}
var bar = {
name: 'bar'
}
foo.sayHello._call(bar, 'Fitz', 'smart')
foo.sayHello._apply(bar, ['Fitz', 'smart'])
var baz = foo.sayHello._bind(bar, 'Fitz', 'smart')
baz()
var testHardBind = foo.sayHello._bind(bar, 'hard', 'bind')
testHardBind._call(Object.create(null)) // hello, get the parms => hard and bind _bind
最後に書く私はただ前端の白を勉強しています.間違っているところがあります.よろしくお願いします.
もしあなたにインスピレーションや助けがあると感じたら、メッセージや関心をお願いします.ありがとうございます.