bind は一回まで
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ 一度 bind したら再 bind できない
◆ できる版 bind + rebind 作ってみた
◆ できる版 bind + rebind 作ってみた
普段はあまり気にしないのですが ライブラリ作ってるときだと bind って上書きできたっけ?と毎回のように確認してしまいます
できるのは 1 回限りで bind 済み関数を bind しても効果はありません
this が {a:1} のオブジェクトになっています
{a:2} のオブジェクトを bind 済みの関数を bind したり call したりしても this は {a:2} から変わりません
ただ new する場合は
新しいコンテキストで実行されます
prototype をうまく使えばできそうと思ったのですが
となって bind 済みの関数の prototype を変更しても意味がないです
元の f 関数を変えれば反映されるのですが 元の f 関数にアクセスできるならそっちを call すればいいので意味がありません
bind 済みの関数しか参照できない場所でコンテキストを設定するということは無理そうです
bind は上書き不可能ないつもの bind ですが rebind 機能のためにちょっと中身が違ってます
rebind はすでに bind されていてもそれを無効にして bind するオブジェクトを設定できます
rebind したときだけ this が変わっています
call, apply は独自のものにしていないので rebind されず bind 済みなら this は変わりません
本来の bind と同じく引数の bind 機能も使えます
できるのは 1 回限りで bind 済み関数を bind しても効果はありません
普通に
function f(msg){
console.log(this, msg)
}
console.log(f.bind({a:1})("bind"))
console.log(f.call({a:1}, "call"))
console.log(f.apply({a:1}, ["apply"]))
{a: 1} "bind"
{a: 1} "call"
{a: 1} "apply"
this が {a:1} のオブジェクトになっています
bind 済みに
const b = f.bind({a:2})
console.log(b.bind({a:3})("bind * 2"))
console.log(b.call({a:3}, "bind + call"))
console.log(b.apply({a:3}, ["bind + apply"]))
{a: 2} "bind * 2"
{a: 2} "bind + call"
{a: 2} "bind + apply"
{a:2} のオブジェクトを bind 済みの関数を bind したり call したりしても this は {a:2} から変わりません
ただ new する場合は
console.log(new b("bind + new"))
f {}
新しいコンテキストで実行されます
prototype をうまく使えばできそうと思ったのですが
b.prototype = {a:4}
new b().a
// undefined
f.prototype = {a:5}
new b().a
// 5
となって bind 済みの関数の prototype を変更しても意味がないです
元の f 関数を変えれば反映されるのですが 元の f 関数にアクセスできるならそっちを call すればいいので意味がありません
bind 済みの関数しか参照できない場所でコンテキストを設定するということは無理そうです
アロー関数
ちなみにアロー関数は this が新しく作られないもので 言い換えれば関数が作られたコンテキストの this を関数作成時に bind してるみたいな動きですconst a = msg => console.log(this, msg)
console.log(a.bind({a:1})("arrow + bind"))
console.log(a.call({a:1}, "arrow + call"))
console.log(a.apply({a:1}, ["arrow + apply"]))
Window {} "arrow * 2"
Window {} "arrow + call"
Window {} "arrow + apply"
rebind
bind でコンテキスト設定したいけど後から bind したら上書きできるようにしたいと思ってこういうの作ってみましたFunction.prototype.bind = function(ctx, ...args) {
const fn = (...a) => {
fn.function.apply(fn.context, [...fn.args, ...a])
}
if (this.context) {
fn.context = this.context
fn.args = [...this.args, ...args]
fn.function = this.function
} else {
fn.context = ctx
fn.args = args
fn.function = this
}
return fn
}
Function.prototype.rebind = function(ctx, ...args) {
const fn = (...a) => {
fn.function.apply(fn.context, [...fn.args, ...a])
}
if (this.context) {
fn.context = ctx
fn.args = [...this.args, ...args]
fn.function = this.function
} else {
fn.context = ctx
fn.ars = args
fn.function = this
}
return fn
}
bind は上書き不可能ないつもの bind ですが rebind 機能のためにちょっと中身が違ってます
rebind はすでに bind されていてもそれを無効にして bind するオブジェクトを設定できます
const c = f.bind({a:2})
console.log(c.rebind({a:3})("bind + rebind"))
console.log(b.call({a:3}, "bind + call"))
console.log(b.apply({a:3}, ["bind + apply"]))
{a: 3} "bind + rebind"
{a: 2} "bind + call"
{a: 2} "bind + apply"
rebind したときだけ this が変わっています
call, apply は独自のものにしていないので rebind されず bind 済みなら this は変わりません
本来の bind と同じく引数の bind 機能も使えます
function d(...args){
console.log(this, ...args)
}
d.bind({a:1}, 1, 2).rebind({a:2}, 3, 4).bind({a:3}, 5)(6)
// {a: 2} 1 2 3 4 5 6