blob: 011c52f76fb147ec089b3d48631529fffe3b9d1e [file] [edit]
function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error('bad value: ' + actual);
}
function shouldThrow(func, errorMessage) {
var errorThrown = false;
var error = null;
try {
func();
} catch (e) {
errorThrown = true;
error = e;
}
if (!errorThrown)
throw new Error('not thrown');
if (String(error) !== errorMessage)
throw new Error(`bad error: ${String(error)}`);
}
// Class methods (strict, no "prototype" property) and object-literal shorthand methods
// use dedicated method structures. Function#bind on them should be strength-reduced
// to NewBoundFunction with lazily materialized .name/.length, and stay correct.
class Component {
constructor() { this.state = 40; }
handleClick(a, b) { return this.state + a + b; }
}
var sloppyHolder = {
handle(a, b, c) { return this === sloppyHolder ? a + b + c : -1; },
};
var component = new Component();
function bindClassMethod() {
return component.handleClick.bind(component, 1);
}
noInline(bindClassMethod);
function bindShorthandMethod() {
return sloppyHolder.handle.bind(sloppyHolder);
}
noInline(bindShorthandMethod);
for (var i = 0; i < testLoopCount; ++i) {
var f = bindClassMethod();
shouldBe(f(1), 42);
shouldBe(f.name, "bound handleClick");
shouldBe(f.length, 1);
var g = bindShorthandMethod();
shouldBe(g(1, 2, 3), 6);
shouldBe(g.name, "bound handle");
shouldBe(g.length, 3);
}
// Methods are not constructors, and neither are their bound versions.
shouldThrow(() => new (bindClassMethod())(), "TypeError: function is not a constructor (evaluating 'new (bindClassMethod())()')");
shouldThrow(() => new (bindShorthandMethod())(), "TypeError: function is not a constructor (evaluating 'new (bindShorthandMethod())()')");
// Once .name/.length are reified (the structure transitions), bind must observe the modified values.
class Modified {
method(a, b) { return a; }
}
var modified = new Modified();
Object.defineProperty(modified.method, "name", { value: "renamed" });
Object.defineProperty(modified.method, "length", { value: 7 });
function bindModifiedMethod() {
return modified.method.bind(null, 0);
}
noInline(bindModifiedMethod);
for (var i = 0; i < testLoopCount; ++i) {
var h = bindModifiedMethod();
shouldBe(h.name, "bound renamed");
shouldBe(h.length, 6);
}