【发布时间】:2021-07-28 12:34:38
【问题描述】:
这个问题是this one 的后续问题。由于某种原因,我在 7 年后回到 JS,我几乎认不出亲爱的老野兽了。
纯粹出于教育目的,我决定重写 Function.prototype.bind() 允许做的各种事情的幼稚实现。这只是一个尝试了解正在发生的事情并引发一些问题的练习。
我很乐意纠正我的示例和 cmets 中的所有错误和误解。
另外,这段代码不是我的。我从博客中得到这个想法,只是稍微调整了一下,但不幸的是我忘记了来源。如果有人认出原件,我很乐意给予应有的信任。同时,我为这个错误道歉。
朴素绑定
最初的想法只是简单地做 lambda 演算专家显然称之为“部分应用程序”的事情,即固定函数的第一个参数的值,该函数也接受隐式的“this”第一个参数,如下所示:
Function.prototype.naive_bind = function (fixed_this, ...fixed_args) {
const fun = this; // close on the fixed args and the bound function
return function(...free_args) { // leave the rest of the parameters free
return fun.call(fixed_this, ...fixed_args, ...free_args);
}
}
绑定构造函数(第一轮)
class class1 {
constructor (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
}
var innocent_bystander = { "huh?":"what?" }
var class2 = class1.naive_bind(innocent_bystander);
class2 (1,2) // exception: class constructor must be invoked with new (as expected)
console.log(new class2(1,2)) // exception: class constructor must be invoked with new (Rats!)
function pseudoclass1 (p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
var pseudoclass2 = pseudoclass1.naive_bind(innocent_bystander);
pseudoclass2 (1,2) // same exception (as expected)
console.log(new pseudoclass2(1,2)) // same again (at least it's consistent...)
Tonnerre de Brest ! 显然运行时不喜欢仅仅基于Function.prototype.call() 的包装器。
似乎真正的bind() 正在添加一些秘密调味料,以使生成的函数具有适当的“构造函数”风味(显然,ECMA 262 规范中的“构造函数”并不意味着类构造函数,而是任何可以调用的函数使用“new”并使用“this”来填充新创建对象的属性和方法)
绑定其他函数
var purefunction1 = console.log
var purefunction2 = purefunction1.naive_bind (null, "Sure,", "but")
purefunction2 ("you can still", "bind pure", "functions")
// sure, but you can still bind pure functions
// ...and make animals talk (by binding simple methods)
var cat = { speech: "meow" }
var dog = { speech: "woof" }
var fish= { speech: "-" }
var talk = function(count) { console.log ((this.speech+", ").repeat(count-1) + this.speech + "!") }
talk.naive_bind (cat,1)(); // meow!
talk.naive_bind (dog,1)(); // woof!
talk.naive_bind (cat)(3) // meow, meow, meow!
talk.naive_bind (fish)(10) // -, -, -, -, -, -, -, -, -, -!
// and bind arrow functions
// ("this" is wasted on them, but their parameters can still be bound)
var surprise = (a,b,c) => console.log (this.surprise, a,b,c)
var puzzlement = surprise.naive_bind(innocent_bystander, "don't", "worry");
// "this" refers to window, so we get our own function as first output.
surprise ("where", "am", "I?") // function surprise(a, b, c) where am I?
// the bound value of this is ignored, but the other arguments are working fine
puzzlement("dude") // function surprise(a, b, c) don't worry dude
显然,一切都按预期进行。还是我错过了什么?
绑定构造函数(第二轮)
我们显然无法将包装器传递给new,但我们可以尝试直接调用new。
由于this 的值是由new 提供的,因此专门构造的包装器只需要担心真正的构造函数参数。
Function.prototype.constructor_bind = function (...fixed_args) {
const fun = this;
return function(...free_args) {
return new fun (...fixed_args, ...free_args);
}
}
var class1_ctor = class1.constructor_bind(1);
console.log (class1_ctor(2)) // class1 { p1:1, p2:2 }
var monster = (a,b) => console.log ("boooh", a, b)
var abomination = monster.constructor_bind(1);
console.log (abomination(2)) // exception: fun is not a constructor (as expected)
嗯,这似乎削减了它。我想真正的bind() 更安全更快,但至少我们可以重现基本功能,即:
- 为方法提供固定值
this - 对任何合法函数进行部分应用,尽管构造函数需要特定的变体
编辑:删除问题以符合 SO 政策。
仅替换为与本文标题匹配的一个,并且我试图通过提供与我认为真正的功能所做的相同且可能错误的等效项来进行探索:
根据 ECMAScript 规范 6.0 版,请帮助我了解原生 Function.prototype.bind() 方法的工作原理。
【问题讨论】:
-
每个问题一个问题。
-
好吧,如果我得到元素来关闭最终列表,我计划编辑帖子。
-
1.也许。但可能不是。 2. 是的。 3.对于不使用
this的函数,.bind()只能作为部分分配。.bind()中几乎没有任何特定于 OOP 的内容。 4. 究竟是什么和什么之间的表现?另请参阅:Which is faster。 5. 提出多个和/或开放式问题不在 SO 的范围内。见help center。 -
好的,我删除了所有结尾的问题。现在可以吗?
-
"请帮助我了解这个函数是如何工作的。" - 哪个函数?那个原生的
bind,你的naive_bind,还是你的constructor_bind?你不了解他们什么?似乎您自己编写了它们,并且它们按预期工作,所以真的不清楚您要的是什么。
标签: ecmascript-6 this bind