我尝试扩展JavaScript Math
。但有一件事让我感到惊讶。
当我尝试按prototype
Math.prototype.randomBetween = function (a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
};
在控制台中我有错误'无法设置属性' randomBetween'未定义的' ...
但是,如果我将此功能赋予Math.__proto__
Math.__proto__.randomBetween = function (a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
};
然后一切正常。
任何人都能解释一下为什么它以这种方式运作吗?我感谢任何帮助。
答案 0 :(得分:30)
Math
不是构造函数,因此它没有prototype
属性:
new Math(); // TypeError: Math is not a constructor
相反,只需将您的方法添加到Math
本身作为own property:
Math.randomBetween = function (a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
};
使用__proto__
的方法有效,因为Math
是Object
个实例,Math.__proto__
是Object.prototype
。
但请注意,您正在向所有对象添加randomBetween
方法,而不仅仅是Math
。这可能会有问题,例如在使用for...in
循环迭代对象时。
答案 1 :(得分:3)
引用this answer:
某些JavaScript实现允许直接访问[[Prototype]]属性,例如通过名为
__proto__
的非标准属性。通常,只能在对象创建期间设置对象的原型:如果通过新的Func()创建新对象,则将设置对象的[[Prototype]]属性到Func.prototype引用的对象。
您无法使用.prototype
分配给原型的原因是因为Math
对象已经创建。
幸运的是,我们可以通过简单地使用:
为Math
对象分配新属性
Math.myFunc = function() { return true };
在您的情况下,这将是:
Math.randomBetween = function(...) { ... };
答案 2 :(得分:1)
那是因为Math
是一个对象,不是一个function
。
在javascript中,function
是面向对象语言中类的粗略等价物。 prototype
是一个特殊属性,允许您将实例方法添加到此类 1 。如果您想扩展该课程,可以使用prototype
,而且#34;只是工作"。
现在让我们考虑Math
是什么。你永远不会创建一个数学对象,你只需使用它的方法。事实上,创建两个不同的Math
对象是没有意义的,因为Math
总是有效!换句话说,javascript中的Math
对象只是将一堆预先编写的数学相关函数组合在一起的便捷方式。它就像一本普通数学字典。
想要向该群组添加内容吗?只需在集合中添加属性即可!这是两种简单的方法。
Math.randomBetween = function() { ... }
Math["randomBetween"] = function() {... }
使用第二种方式使它更加明显,它是一个字典类型集合,但它们都做同样的事情。
答案 3 :(得分:0)
var MyMath = Object.create(Math); // empty object with prototype Math
MyMath.randomBetween = function (a, b) {
return this.floor(this.random() * (b - a + 1) + a);
};
typeof(MyMath); // object
Object.getPrototypeOf(MyMath); // Math
MyMath.PI; // 3.14...
MyMath.randomBetween(0, 10); // exactly that
Math
对象是新MyMath
对象MyMath
可以访问Math
MyMath
Math
this
来引用Math
功能这种方法没有 Monkey Patching 。这是扩展JavScript Math
的最佳方法。没有必要重复其他答案的解释。