prototipos prototipada objetos herencia es6 ejemplos crear clases javascript math prototype built-in

prototipada - javascript prototype



Extender el objeto matemático a través del prototipo no funciona (4)

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 consola tengo el error ''No se puede establecer la propiedad'' randomBetween ''de undefined'' ...

Pero si asigno esta función 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? Aprecio cualquier ayuda.


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

En javascript, una function es el equivalente aproximado de una clase en lenguajes orientados a objetos. prototype es una propiedad especial que le permite agregar métodos de instancia a esta clase 1 . Cuando quieres extender esa clase, usas prototype y "simplemente funciona".

Ahora pensemos qué es la Math . Nunca creas un objeto matemático, solo usas sus métodos. De hecho, no tiene sentido crear dos objetos Math diferentes, ¡porque la Math siempre funciona de la misma manera! En otras palabras, el objeto Math en javascript es solo una forma conveniente de agrupar un montón de funciones relacionadas con las matemáticas preescritas. Es como un diccionario de matemáticas comunes.

¿Quieres agregar algo a ese grupo? ¡Simplemente añada 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 tipos de diccionarios, pero ambas hacen lo mismo.


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 configurar el prototipo de un objeto durante la creación del objeto: si crea un nuevo objeto a través de la nueva función Func (), la propiedad [[Prototype]] del objeto se establecerá en el objeto referenciado por Func.prototype.

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

Afortunadamente para nosotros, podemos asignar nuevas propiedades al objeto Math simplemente usando:

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

En tu caso, esto sería:

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


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

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

En su lugar, solo agrega tu método a Math sí mismo como una propiedad propia :

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

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

Pero luego note que está agregando el método randomBetween a todos los objetos, no solo a Math . Esto puede ser problemático, por ejemplo, al iterar objetos con un bucle for...in .


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 objeto Math es el prototipo del nuevo objeto MyMath
  • MyMath tiene acceso a todas las funcionalidades de Math
  • Puedes agregar tu funcionalidad personalizada a MyMath sin manipular Math
  • dentro de sus métodos personalizados, use la palabra clave this para referirse a la funcionalidad Math

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