考虑以下创建两个类
Point
和 YAxisPoint
的用例:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return `${this.x},${this.y}`;
};
var p = new Point(1, 2);
var YAxisPoint = Point.bind(null, 0);
var axisPoint = new YAxisPoint(5);
console.log(p.toString()); // '1,2'
console.log(axisPoint.toString()); // '0,5'
在浏览器中执行此代码会产生正确的结果。现在假设我想重写
toString
构造函数的 YAxisPoint
函数:
YAxisPoint.prototype.toString = function() { return 'override'; }
var newAxisPoint = new YAxisPoint(5);
console.log(newAxisPoint.toString()); // 'override'
在浏览器中执行此代码会产生:
未捕获类型错误:无法设置未定义的属性“toString”
问题1
为什么
YAxisPoint
的原型是未定义的?
我真的不明白。如果我添加以下填充,它将按预期工作。
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
问题2
浏览器的绑定实现是否存在错误?我在 Opera、Safari、Chrome 和 Firefox 中尝试过,它们都有同样的问题。
这是您可以运行来测试的代码的链接。
这个沙箱中的polyfill被注释掉了。您可以取消注释来验证。
使用
Reflect.construct()
并将.toString()
设置为.__proto__
的
axisPoint
即可达到预期效果
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return `${this.x},${this.y}`;
};
var p = new Point(1, 2);
var axisPoint = Reflect.construct(Point.bind(null /* Point */, 0), [5]);
console.log(p.toString()); // '1,2'
console.log(axisPoint.toString()); // '0,5'
axisPoint.__proto__.toString = function() {
return 'override';
}
console.log(axisPoint.toString());