Extender el object matemático a través del prototipo no funciona

Intento extender JavaScript Math . Pero una cosa me sorprendió.

Cuando intenté extenderlo por prototype

 Math.prototype.randomBetween = function (a, b) { return Math.floor(Math.random() * (b - a + 1) + a); }; 

En la console tengo el error 'No se puede establecer la propiedad' randomBetween 'de undefined' …

Pero si asigne esta function a Math.__proto__

 Math.__proto__.randomBetween = function (a, b) { return Math.floor(Math.random() * (b - a + 1) + a); }; 

Entonces todo funciona bien.

¿Alguien puede explicarme por qué funciona de esta manera? Agradezco cualquier ayuda.

Math no es un constructor, por lo que no tiene propiedad de prototype :

 new Math(); // TypeError: Math is not a constructor 

En su lugar, simplemente agregue su método a Math como propiedad propia :

 Math.randomBetween = function (a, b) { return Math.floor(Math.random() * (b - a + 1) + a); }; 

Su enfoque con __proto__ funciona porque, como Math es una instancia de Object , Math.__proto__ es Object.prototype .

Pero observe que está agregando método randomBetween a todos los objects, no solo a Math . Esto puede ser problemático, por ejemplo, al iterar objects con un ciclo for...in .

Para citar esta respuesta :

Algunas implementaciones de JavaScript permiten el acceso directo a la propiedad [[Prototype]], por ejemplo, a través de una propiedad no estándar llamada __proto__ . En general, solo es posible establecer el prototipo de un object durante la creación del object: si crea un nuevo object a través del nuevo Func (), la propiedad del object [[Prototype]] se establecerá en el object al que hace reference Func.prototype.

La razón por la que no puede asignar su prototipo con .prototype es porque el object Math ya se ha creado.

Afortunadamente para nosotros, podemos asignar nuevas properties al object Math simplemente usando:

 Math.myFunc = function() { return true }; 

En tu caso, esto sería:

 Math.randomBetween = function(...) { ... }; 

Eso es porque hay Math es un object, no una function .

En javascript, una function es el equivalente aproximado de una class en lenguajes orientados a objects. prototype es una propiedad especial que le permite agregar methods de instancia a esta class 1 . Cuando desea extender esa class, usa un prototype y "simplemente funciona".

Ahora pensemos en lo que es Math . Nunca creas un object matemático, solo usas sus methods. De hecho, no tiene sentido crear dos objects Math diferentes, ¡porque las Math siempre funcionan igual! En otras palabras, el object Math en javascript es solo una manera conveniente de agrupar un set de funciones matemáticas escritas previamente. Es como un dictionary de matemática común.

¿Quieres agregar algo a ese grupo? ¡Solo agrega una propiedad a la colección! Aquí hay dos maneras fáciles de hacerlo.

 Math.randomBetween = function() { ... } Math["randomBetween"] = function() {... } 

Usar la segunda forma hace que sea un poco más obvio que es una colección de tipo dictionary, pero ambos hacen lo mismo.

 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 
  • el object Math es el prototipo del nuevo object MyMath
  • MyMath tiene acceso a todas las funciones de Math
  • puede agregar su funcionalidad personalizada a MyMath sin manipular Math
  • dentro de sus methods personalizados, use la palabra key this para referirse a la funcionalidad Math

No hay Monkey Patching con este enfoque. Esta es la mejor manera de extender las Math JavScript. No hay necesidad de repetir las explicaciones de las otras respuestas.

    Intereting Posts