Есть ли практическая польза от переопределения Math.constructor в JavaScript/ActionScript?

Объект Math не имеет свойства прототипа, но имеет свойство конструктора. Есть ли случай, когда переопределение конструктора было бы полезно?


person Paul Sweatte    schedule 26.04.2012    source источник
comment
Math.constructor === Object // true ... Math.constructor идентично Object, поэтому Math.constructor("foo") идентично Object("foo").   -  person Dagg Nabbit    schedule 07.05.2012


Ответы (8)


MDN говорит:

В отличие от других глобальных объектов, Math не является конструктором. Все свойства и методы Math являются статическими.

В других языках, когда класс является статическим, вы можете напрямую использовать его свойства и методы, не создавая экземпляр этого класса (объект). Если используется математический конструктор, нет собственного типа для поддержки объекта, в отличие от примитивных типов: Number, String, Boolean. Их можно преобразовать в объекты с помощью их оберток.

Кроме того, расширение корневого объекта является плохой практикой. Если в будущем в среде будет реализована новая функциональность и в коде не будет проверки на отказоустойчивость для этого, она переопределит нативную.

Мое личное мнение, что вы не конструктор и не прототип - вы можете определять свои собственные математические функции. Объект Math здесь просто для представления стандартных функций и дает программистам возможность не определять, например, Pi или E. И, вероятно, пользовательская математическая функция будет в несколько раз медленнее встроенной.

person Bakudan    schedule 03.05.2012
comment
Итак, если свойства и методы Math статичны, в чем опасность их расширения путем определения собственного прототипа и конструктора? - person Paul Sweatte; 03.05.2012
comment
Для прототипа - может и будет в будущем, кто знает; в будущем стандарт может определять что-то новое, интегральное или что-то в этом роде. Но я не вижу смысла в конструкторе - нет математического типа для поддержки объекта, созданного Math.constructor(). - person Bakudan; 04.05.2012

Объект 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.

person PointedEars    schedule 07.05.2012
comment
Так почему же Math.constructor === Object имеет значение true, а Object.getPrototypeOf(Math) === Math.constructor() — false? - person Paul Sweatte; 07.05.2012
comment
@PaulSweatte, в этом нет смысла. Когда Object.getPrototypeOf(x) всегда равно x.constructor (или x.constructor()) при любых нормальных обстоятельствах? - person Dagg Nabbit; 07.05.2012
comment
@PaulSweatte, может быть, ты хотел проверить Object.getPrototypeOf(Math) === Math.constructor.prototype? - person Dagg Nabbit; 08.05.2012

Все объекты имеют свойство constructor, указывающее конструктор, создавший объект.

Даже ({}).constructor возвращает Object().

person SLaks    schedule 26.04.2012
comment
Пожалуйста, измените его на обычный. Вы могли бы delete Object.prototype.constructor. Кроме того, свойство constructor часто отсутствует/неверно, когда прототипы устанавливаются с помощью Constructor.prototype = {...}. - person Bergi; 27.04.2012
comment
@Bergi delete Object.prototype.constructor не лучшая идея. Однако вы можете создать объект, который имеет пустую цепочку прототипов и, следовательно, не наследует никаких свойств. Такой объект полезен в качестве контейнера данных, поскольку маловероятно, что возникнут конфликты имен свойств. Начиная с версии 5 это возможно без использования проприетарного свойства __proto__. Например, Object.create(null).constructor равно undefined. - person PointedEars; 07.05.2012

На самом деле, Math не имеет своего собственного свойства "конструктор". Он наследует «конструктор» от Object.prototype, точно так же, как он наследует «toString», «hasOwnProperty» и все другие свойства Object.prototype.

Для математики «конструкция», вероятно, имеет очень мало пользы. Это просто следствие того, как работает наследование в JavaScript.

person Allen Wirfs-Brock    schedule 27.04.2012
comment
У математики нет прототипа, так как же она наследует? - person Paul Sweatte; 27.04.2012
comment
@PaulSweatte: прототипом Math является Object. - person SLaks; 29.04.2012
comment
Math.prototype возвращает неопределенное значение. - person Paul Sweatte; 29.04.2012
comment
@PaulSweatte Отметьте Math.__proto__ или используйте Object.getPrototypeOf(Math). Оба идентичны Object. - person Rob W; 03.05.2012
comment
Итак, Math.__proto__ и Object.getPrototypeOf(Math) равны Math.constructor(). - person Paul Sweatte; 03.05.2012
comment
@PaulSweatte нет, они не равны. 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, как здесь (...ну вроде):

  1. Math --> Math.hasOwnProperty('constructor')=== false

  2. НЕ НАЙДЕНО ПЕРЕЙТИ СЛЕДУЮЩИЙ

  3. Math.__proto__ --> Math.__proto__.hasOwnProperty('constructor')=== true

  4. НАЙДЕНО, ВОЗВРАТ: 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

person ckozl    schedule 07.05.2012

На мой взгляд, объект Math в JavaScript пытается имитировать статическое поведение Math в других популярных языках программирования (например, Java). Поскольку это можно смоделировать только в JavaScript, а все объекты имеют свойства прототипа и конструктора по умолчанию, я предполагаю, что разработчики просто забыли установить для свойства конструктора значение undefined, явно выполнив что-то вроде Math.constructor = undefined;.

person maddob    schedule 07.05.2012

В ситуации, когда вам нужно сгенерировать таблицу преобразования, не загрязняя глобальную область, это было бы полезно. Например:

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... 

Ссылки

person Paul Sweatte    schedule 15.07.2014

   <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» будет указывать? Если вы сможете найти ответ на этот вопрос, у вас будет что-то с целью, которую вы сможете запрограммировать.

person Thalaivar    schedule 03.05.2012
comment
Почему вы хотите изменить конструктор, суть вопроса? Ресиг затронул кое-что много лет назад, и как можно улучшить эту идею? - person Paul Sweatte; 04.05.2012
comment
@PaulSweatte, кто говорит, что вам нужно изменить конструктор, если вы не меняете прототип? А зачем вам менять прототип статического объекта? Продлить? Что ж, поскольку он статичен, вы можете просто расширить его, добавив собственные методы/свойства. Зачем усложнять? И, кстати, я не мог понять, при чем здесь идея Ресига - она ​​была связана с "воровством встроенного функционала"? - person Parth Thakkar; 05.05.2012
comment
В этой идее использовались встроенные функции Math для улучшения Array, поэтому вопрос в том, можно ли это сделать лучше? - person Paul Sweatte; 07.05.2012
comment
Math.prototype = Math не имеет смысла. Math не является конструктором, поэтому присвоение ему свойства прототипа ничего не делает. Вы просто перезаписали свойство rand Math и добавили самоссылающееся свойство prototype, которое не имеет смысла. - person Dagg Nabbit; 08.05.2012
comment
В этом ответе так много неправильного, что я почти не знаю, с чего начать. Функции являются объектами. Свойство prototype экземпляра Function используется неявно только при построении объекта; это не доказательство того, что объект имеет непустую цепочку прототипов, а ее отсутствие не является доказательством обратного; объект Math определенно имеет его, поэтому он может наследовать свойство constructor. И так далее. Ответ говорит, что вопрос бессмысленный. Ну, ответ полностью не соответствует сути вопроса. - person PointedEars; 08.05.2012