Объект Math не имеет свойства прототипа, но имеет свойство конструктора. Есть ли случай, когда переопределение конструктора было бы полезно?
Есть ли практическая польза от переопределения Math.constructor в JavaScript/ActionScript?
Ответы (8)
MDN говорит:
В отличие от других глобальных объектов, Math не является конструктором. Все свойства и методы Math являются статическими.
В других языках, когда класс является статическим, вы можете напрямую использовать его свойства и методы, не создавая экземпляр этого класса (объект). Если используется математический конструктор, нет собственного типа для поддержки объекта, в отличие от примитивных типов: Number, String, Boolean. Их можно преобразовать в объекты с помощью их оберток.
Кроме того, расширение корневого объекта является плохой практикой. Если в будущем в среде будет реализована новая функциональность и в коде не будет проверки на отказоустойчивость для этого, она переопределит нативную.
Мое личное мнение, что вы не конструктор и не прототип - вы можете определять свои собственные математические функции. Объект Math здесь просто для представления стандартных функций и дает программистам возможность не определять, например, Pi
или E
. И, вероятно, пользовательская математическая функция будет в несколько раз медленнее встроенной.
Объект Math
(точнее: объект, на который ссылается начальное значение свойства Math
глобального объекта ECMAScript) не имеет свойство constructor
, см. Спецификация языка ECMAScript, редакция 5.1, раздел 15.8 «Математический объект». Следовательно,
Math.hasOwnProperty("constructor")
возвращает false
(в соответствующих реализациях ECMAScript Ed. 3 и выше).
Объект Math
наследует свойство constructor
через цепочку прототипов от своего прототипа, который является «стандартным встроенным объектом-прототипом Object (15.2.4)» (там же), который совпадает с исходным. на который ссылается свойство Object.prototype
. Последний объект предоставляет несколько полезных свойств, таких как Object.prototype.hasOwnProperty
(см. выше). Поэтому имеет смысл, что цепочка прототипов объекта Math
вместо этого не пуста.
То, что объект Math
также наследует Object.prototype.constructor
, является просто побочным эффектом этого безусловного наследования в реализациях ECMAScript, поскольку (за исключением реализаций предложения редакции 4 и, возможно, будущих редакций) свойства не имеют подходящего модификатора видимости для предотвращения этого. (например, private
в нескольких языках, основанных на классах). И, конечно же, конструктор экземпляров Object
, которые наследуются от одного и того же прототипа, является объектом, на который ссылается начальное значение свойства Object
глобального объекта. Так что Object.prototype.constructor
должно отражать это. Поэтому результат оценки
Math.constructor === Object
is true
.
Object.getPrototypeOf(x)
всегда равно x.constructor
(или x.constructor()
) при любых нормальных обстоятельствах?
- person Dagg Nabbit; 07.05.2012
Object.getPrototypeOf(Math) === Math.constructor.prototype
?
- person Dagg Nabbit; 08.05.2012
Все объекты имеют свойство constructor
, указывающее конструктор, создавший объект.
Даже ({}).constructor
возвращает Object()
.
delete Object.prototype.constructor
. Кроме того, свойство constructor
часто отсутствует/неверно, когда прототипы устанавливаются с помощью Constructor.prototype = {...}
.
- person Bergi; 27.04.2012
delete Object.prototype.constructor
не лучшая идея. Однако вы можете создать объект, который имеет пустую цепочку прототипов и, следовательно, не наследует никаких свойств. Такой объект полезен в качестве контейнера данных, поскольку маловероятно, что возникнут конфликты имен свойств. Начиная с версии 5 это возможно без использования проприетарного свойства __proto__
. Например, Object.create(null).constructor
равно undefined
.
- person PointedEars; 07.05.2012
На самом деле, Math не имеет своего собственного свойства "конструктор". Он наследует «конструктор» от Object.prototype, точно так же, как он наследует «toString», «hasOwnProperty» и все другие свойства Object.prototype.
Для математики «конструкция», вероятно, имеет очень мало пользы. Это просто следствие того, как работает наследование в JavaScript.
Math
является Object
.
- person SLaks; 29.04.2012
Math.__proto__
или используйте Object.getPrototypeOf(Math)
. Оба идентичны Object
.
- person Rob W; 03.05.2012
Math.__proto__
— это старый добрый объект. Math.constructor
равно Object
, поэтому Math.constructor()
возвращает другой простой старый объект, эквивалентный, но не равный Math.__proto__
.
- person Dagg Nabbit; 08.05.2012
Math
объект "наследует" от Object
(что означает Math.__proto__ === Object.prototype
)
Объект Math
для любого программиста на JavaScript не более чем "особый", но простой 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
надеюсь, это поможет -ck
На мой взгляд, объект Math в JavaScript пытается имитировать статическое поведение Math в других популярных языках программирования (например, Java). Поскольку это можно смоделировать только в JavaScript, а все объекты имеют свойства прототипа и конструктора по умолчанию, я предполагаю, что разработчики просто забыли установить для свойства конструктора значение 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"]
Другим использованием может быть расширение свойств и методов для определения примитивов для библиотеки графов:
root(arg,index) "index-th" root of argument. Example: root(x,6) sixth root of x, root[tan(x),4] fourth root of the tangent of x. sqrt() Square root of argument (number or expression inside the parentheses). Equivalent to root(argument,2) cbrt() Cube root of argument. Equivalent to root(argument,3) logn(arg,base) Logarithm base-base of arg. ln() Natural logarithm of argument (base-E logarithm of argument where E is Euler's constant) lg() Logarithm base-10 of argument, equivalent to logn(argument,10). lb() Logarithm base-2 of argument. exp() Exponential Function E to the power of argument, equivalent to E^argument sin() Sine of argument cos() Cosine tan() Tangent cot() Cotangent sec() Secant of argument, equiv. to 1/cos(arg). csc() Cosecant, equiv. to 1/sin(arg). asin() Arc sine acos() Arc cosine atan() Arc tangent acot() Arc cotangent asec() Arc secant, inverse secant. acsc() Arc cosecant, inverse cosecant. sinh() Hyperbolic sine, Sinus hyperbolicus cosh() Hyperbolic cosine, Cosinus hyperbolicus tanh() Hyperbolic tangent, Tangens hyperbolicus coth() Hyperbolic cotangent, Cotangens hyperbolicus sech() Hyperbolic secant, Secans hyperbolicus. csch() Hyperbolic cosecant, Cosecans hyperbolicus. asinh() Area sine, Area sinus hyperbolicus, inverse sinh(). acosh() Area cosine, Area cosinus hyperbolicus, inverse cosh(). atanh() Area tangent, Area tangens hyperbolicus, inverse tanh(). acoth() Area cotangent, Area cotangens hyperbolicus, inverse cotanh(). asech() Area- secant, Area secans hyperbolicus, inverse sech(). acsch() Area- cosecant, Area cosecans hyperbolicus, inverse csch(). gaussd(x,mean,sigma) Gaussian distribution ("Bell Curve"). gaussd(x,0,1), by the way, is the special case "Normal distribution density with mean-value=0, standard-deviation=1". min(arg1,arg2) Returns the lesser of the two arguments max(arg1,arg2) Returns the greater of the two arguments round() Rounds argument up or down to the closest integer floor() Rounds arg down. ceil() Rounds arg up. abs() or | | Absolute value of argument. Example: 2abs(sin[x]) or alternatively 2|sin(x)| . sgn() Sign Function.
rand Random number between 0 und 1. Example: pi*rand*sin(x) or even Pirandsin(x) . E Euler's constant 2.718281828459045... LN2 Natural logarithm of 2, is 0.6931471805599453... LN10 Natural logarithm of 10, is 2.302585092994046... LOG2E Base-2 logarithm of E (E: see above), is 1.4426950408889633... LOG10E Base-10 logarithmus of E, is 0.4342944819032518... PHI Golden Ratio 1.61803398874989... PI 3.141592653589793... SQRT1_2 Square root of 1/2, is 0.7071067811865476... SQRT2 Square root of 2, is 1.4142135623730951...
Ссылки
<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, заключается в том, что это не функция, а скорее объект. Поскольку вы можете использовать новые String()
и новые Array()
, вы также можете использовать String.prototype
и Array.prototype
.
То же самое касается Object, Function, Number, Date, RegExp and even Boolean
. Однако любой определенной функции будет присвоено свойство прототипа, и она будет наследоваться от Function и всего остального в цепочке, от которого она должна наследоваться.
Если вы хотите рассматривать Math
как функцию, все, что вам нужно сделать, это переопределить переменную с помощью функции. Таким образом, Math.constructor
не будет возвращать Object при вызове, поскольку он фактически будет связан с вашей пользовательской функцией, которая его создала.
Вы можете сначала сделать копию собственного объекта, а затем передать его одному из свойств прототипа вашей переопределяющей функции или использовать инкапсуляцию, чтобы только ваша новая функция Math могла получить доступ к собственным методам. Не знаю, что еще можно сказать по теме.
Начальный вопрос какой-то бессмысленный. Math.constructor вернет Object и будет аналогичен прямому вызову Object. Единственное отличие будет в том, если вы измените конструктор.
Почему вы все равно хотите изменить конструктор?
Объект Math
прекрасно выглядит таким, какой он есть. Если бы мы ожидали, что он что-то откуда-то унаследует, на что бы мы вообще ожидали, что «this
» будет указывать? Если вы сможете найти ответ на этот вопрос, у вас будет что-то с целью, которую вы сможете запрограммировать.
Math.prototype = Math
не имеет смысла. Math
не является конструктором, поэтому присвоение ему свойства прототипа ничего не делает. Вы просто перезаписали свойство rand
Math
и добавили самоссылающееся свойство prototype
, которое не имеет смысла.
- person Dagg Nabbit; 08.05.2012
prototype
экземпляра Function
используется неявно только при построении объекта; это не доказательство того, что объект имеет непустую цепочку прототипов, а ее отсутствие не является доказательством обратного; объект Math
определенно имеет его, поэтому он может наследовать свойство constructor
. И так далее. Ответ говорит, что вопрос бессмысленный. Ну, ответ полностью не соответствует сути вопроса.
- person PointedEars; 08.05.2012
Math.constructor === Object // true
...Math.constructor
идентичноObject
, поэтомуMath.constructor("foo")
идентичноObject("foo")
. - person Dagg Nabbit   schedule 07.05.2012