这个问题是这一个的后续问题.由于某种原因,7年后我又要回到JS了,我几乎认不出这只可爱的老野兽了。
纯粹出于教育目的,我决定重写Function.prototype.bind()允许做的各种事情的天真实现。这只是一个练习,试图了解发生了什么,并引发一些问题。
对于我的例子和评论中的所有错误和误解,我很乐意得到纠正。
而且,这个代码不是我的。我从一个博客中得到了这个想法,只是稍微修改了一下,但不幸的是,我失去了对源的了解。如果有人认出了原件,我很乐意给予应有的赞扬。同时,我为这个错误道歉。
朴素绑定
最初的想法是简单地执行lambda微积分显然将其称为“部分应用程序”的操作,即修复函数的第一个参数的值,该函数还接受一个隐式的“这个”第一个参数,如下所示:
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...)显然,布列斯特!运行时对仅仅基于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政策。
取而代之的只有一个,那个与这个帖子的标题相匹配的,我试图通过提供一个天真的,可能是错误的,相当于我认为真正的功能所做的事情来探索:
根据Function.prototype.bind()规范的6.0版本,请帮助我理解本机ECMAScript方法是如何工作的。
发布于 2021-07-28 16:56:50
您所缺少的唯一一点是在new.target中引入了ES6,这使得区分function中的[ call ]和[构造]成为可能,而b)需要在new调用中转发。
因此,更完整的填充可能如下所示:
Function.prototype.bind = function (fixed_this, ...fixed_args) {
const fun = this;
return function(...free_args) {
return new.target != null
? Reflect.construct(fun, [...fixed_args, ...free_args], new.target)
: fun.call(fixed_this, ...fixed_args, ...free_args);
}
}其他一些细节涉及到,fun被断言为一个函数对象,并且返回的绑定函数具有一个特殊的.name,一个精确的.length,而没有.prototype。你可以在规范中找到这些东西,显然你已经读过了。
https://stackoverflow.com/questions/68560498
复制相似问题