Math对象没有原型属性,但有构造函数属性。是否存在重新定义构造函数的情况会很有用?
Math对象没有原型属性,但有构造函数属性。是否存在重新定义构造函数的情况会很有用?
在ECMAScript全局对象的Math
属性的初始值所引用的对象中,Math
对象(确切地说)没有constructor
属性,详见ECMAScript语言规范5.1版,第15.8节“Math对象”。因此,
Math.hasOwnProperty("constructor")
在符合ECMAScript Ed.3及更高版本的实现中,返回false
。
Math
对象通过原型链从其原型继承了constructor
属性,其原型是“标准内置Object原型对象(15.2.4)”(如上所述),这与最初由Object.prototype
属性引用的相同。后者提供了几个有用的属性,例如Object.prototype.hasOwnProperty
(见上文)。因此,Math
对象的原型链不是空的,这是有意义的。
Math
对象还继承了Object.prototype.constructor
,这只是ECMAScript实现中无条件继承的副作用(除了Edition 4提案的实现和可能的未来版本之外,属性没有适当的可见性修饰符来防止这种情况,就像几种基于类的语言中的private
一样)。当然,继承自相同原型的Object
实例的构造函数是全局对象的Object
属性的初始值所引用的对象。因此,Object.prototype.constructor
必须反映这一点。因此,评估结果为
Math.constructor === Object
是true
。
Object.getPrototypeOf(x)
何时等于 x.constructor
(或 x.constructor()
)? - Dagg NabbitObject.getPrototypeOf(Math) === Math.constructor.prototype
? - Dagg NabbitObject.prototype.constructor
不是一个好主意。但是,您可以创建一个具有空原型链的对象,因此不继承任何属性。这样的对象作为数据容器非常有用,因为几乎没有任何属性名称冲突的可能性。自第5版以来,可以在不使用专有的 __proto__
属性的情况下实现此操作。例如,Object.create(null).constructor
是 undefined
。 - PointedEarsMath
的原型是Object
。 - SLaksMath.__proto__
,或使用 Object.getPrototypeOf(Math)
。两者都等同于 Object
。 - Rob WMath.__proto__
是一个普通对象。 Math.constructor
是 Object
,因此 Math.constructor()
返回另一个普通对象,它等效但不等于Math.__proto__
。 - Dagg NabbitMath
对象“继承”自Object
(意味着Math.__proto__ === Object.prototype
)。
对于任何JavaScript程序员来说,Math
对象不过是一个“特殊”的但简单的Object
,其方法的实现和构造都是自动和隐藏的。
Object.prototype
定义了一个.constructor
字段(实际上任何函数都会将自己分配给其自己原型的构造函数,请参见ex1)
ex1(稍微有些弯路):
function xxx() { }
// then:
xxx.prototype.constructor === xxx; // true
// since xxx is a function:
xxx.constructor === Function.prototype.constructor; // true
// and as such:
xxx.constructor === Function; // true
Math.constructor
时,它只是像这样查找Math
对象的原型链(...嗯,有点像):
Math
--> Math.hasOwnProperty('constructor')
=== false
未找到,移至下一个
Math.__proto__
--> Math.__proto__.hasOwnProperty('constructor')
=== true
找到,返回:Math.__proto__.constructor
Math.constructor === Object.prototype.constructor; // true
// and as such:
Math.constructor === Object; // true
// and as stated at the top:
Math.__proto__ === Object.prototype; // true
MDN表示:
与其他全局对象不同,Math不是构造函数。Math的所有属性和方法都是静态的。
在其他语言中,当一个类是静态的时,你可以直接使用它的属性和方法,而不需要创建该类(即对象)的实例。如果使用Math构造函数,则没有本地类型支持该对象,不像原始类型:Number、String、Boolean。它们可以使用其包装器转换为对象。
此外,扩展根对象是一种不好的做法。如果将来在环境中实现新功能并且代码没有对此进行故障安全检查,它将覆盖本机功能。
我个人的观点是您不需要构造函数,也不需要原型 - 您可以定义自己的数学函数。 Math对象仅在此处提供标准函数,并使程序员能够不定义例如Pi
或E
。可能用户定义的数学函数比内置函数慢几倍。
undefined
,通过显式执行类似于 Math.constructor = undefined;
的操作来实现。Math.constructor = function() {
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
//Loop through code points
while (i < max) {
//Convert decimal to hex value, find the character, then pad zeroes to the codepoint
Math.constructor[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
}
调用构造函数以填充它,如下所示:
Math.constructor();
Math.constructor["a"]
<script type="text/javascript">
Math.prototype=Math;
Math.prototype.rand=function(min,max){
return Math.floor((Math.random() * (max-min+1))+min)
}
var o=[];
for(var i=0;i<100;i++)o.push(Math.rand(-1,1));
alert(o.join(", "))
</script>
当然,你也可以这样做:
Math.rand=function(min,max){
return Math.floor((Math.random() * (max-min+1))+min)
}
Math没有像Array和String一样带有自己的原型,这是因为它不是一个函数而是一个对象。由于你可以使用new String()
和new Array()
,所以你也能够使用String.prototype
和Array.prototype
。
对于Object、Function、Number、Date、RegExp甚至Boolean
都是一样的。然而,任何定义的函数都将被分配一个原型属性,并从Function和其他链中继承。
如果你想把Math
当作一个函数来处理,你只需要用一个函数覆盖变量。这样,当调用Math.constructor
时,它将不会返回Object,因为它实际上是链接到你创建的用户定义函数。
你可以先复制原生对象,然后将其丢到你重写函数的原型属性之一,或者使用封装,这样只有你的新Math函数才能访问原生方法。关于这个主题,不确定还能说什么。
开头的问题有点无意义。当调用Math.constructor时,将返回Object,并且与直接调用Object相同。唯一的区别是如果你改变了构造函数。
为什么你想要改变构造函数呢?Math
对象现在的状态已经很好了。如果我们期望它从某个地方继承一些东西,那么我们会期望 "this
" 指向哪里呢?如果你能回答这个问题,你就可以编写有用的代码了。Math.prototype = Math
没有意义。 Math
不是一个构造函数,因此给它一个原型属性不会产生任何效果。你只是覆盖了 Math
的 rand
属性,并添加了一个没有任何作用的自引用 prototype
属性。 - Dagg NabbitFunction
实例的 prototype
属性仅在对象构造时隐式使用;它并不能证明一个对象具有非空的原型链,也不能证明其缺少;例如 Math
对象显然有一个,这就是它能够继承 constructor
属性的原因。此外还有其他问题。答案说这个问题 "有点毫无意义",但是它完全没有理解问题的关键点。 - PointedEars
Math.constructor === Object // true
...Math.constructor
дЄОObject
зЫЄеРМпЉМеЫ†ж≠§Math.constructor("foo")
дЄОObject("foo")
зЫЄеРМгАВ - Dagg Nabbit