¿Javascript tiene algo así como la función method_missing de Ruby?

En Ruby, creo que puede llamar a un método que no se ha definido y, sin embargo, capturar el nombre del método llamado y hacer el procesamiento de este método en tiempo de ejecución.

¿Puede Javascript hacer el mismo tipo de cosas?

La función de ruby ​​que está explicando se llama “method_missing” http://rubylearning.com/satishtalim/ruby_method_missing.htm .

Es una característica nueva que está presente solo en algunos navegadores como Firefox (en el motor Javascript de araña mono). En SpiderMonkey se llama “__noSuchMethod__” https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod

Lea este artículo de Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ para obtener más detalles sobre la próxima implementación.

method_missing no encaja bien con JavaScript por la misma razón que no existe en Python: en ambos lenguajes, los métodos son solo atributos que resultan ser funciones; y los objetos a menudo tienen atributos públicos que no se pueden llamar. Contraste con Ruby, donde la interfaz pública de un objeto es 100% de métodos.

Lo que se necesita en JavaScript es un gancho para obtener acceso a los atributos que faltan, ya sean métodos o no. Python lo tiene: vea el método especial __getattr__ .

La propuesta __noSuchMethod__ de Mozilla introdujo otra inconsistencia en un lenguaje plagado de ellos.

El camino a seguir para JavaScript es el mecanismo Proxy (también en ECMAscript Harmony ), que está más cerca del protocolo de Python para personalizar el acceso a los atributos que de la eliminación de métodos de Ruby.

No por el momento, no. Hay una propuesta para ECMAScript Harmony, llamada proxies , que implementa una característica similar (en realidad, mucho más poderosa), pero ECMAScript Harmony aún no ha salido y probablemente no lo será en un par de años.

method_missing una biblioteca para javascript que te permite usar method_missing en javascript: https://github.com/twigdis/unmiss

Utiliza los Proxies ES6 para funcionar. Aquí hay un ejemplo que usa herencia de Clase ES6. Sin embargo, también puedes usar decoradores para lograr los mismos resultados.

 import { MethodMissingClass } from 'unmiss' class Example extends MethodMissingClass { methodMissing(name, ...args) { console.log(`Method ${name} was called with arguments: ${args.join(' ')}`); } } const instance = new Example; instance.what('is', 'this'); > Method what was called with arguments: is this 

No, no hay una capacidad de metaprogtwigción en javascript directamente análoga al método method_missing hook de ruby. El intérprete simplemente genera un error que el código de llamada puede detectar pero no puede ser detectado por el objeto al que se accede. Aquí hay algunas respuestas sobre la definición de funciones en tiempo de ejecución, pero eso no es lo mismo. Puedes hacer muchas metaprogtwigciones, cambiar instancias específicas de objetos, definir funciones, hacer cosas funcionales como memorizar y decoradores. Pero no hay una metaprogtwigción dinámica de las funciones que faltan como las que hay en ruby ​​o python.

Llegué a esta pregunta porque estaba buscando una forma de pasar a otro objeto si el método no estaba presente en el primer objeto. No es tan flexible como lo que preguntas; por ejemplo, si falta un método en ambos, se producirá un error.

Estaba pensando en hacer esto para una pequeña biblioteca que tengo que ayuda a configurar los objetos extjs de una manera que también los hace más comprobables. Tuve llamadas separadas para obtener los objetos para la interacción y pensé que esta podría ser una buena forma de unir esas llamadas al devolver un tipo aumentado

Puedo pensar en dos formas de hacer esto:

Prototipos

Puedes hacer esto usando prototipos, ya que las cosas caen en el prototipo si no están en el objeto real. Parece que esto no funcionaría si el conjunto de funciones que desea utilizar utiliza la palabra clave this: obviamente su objeto no sabrá o no le importará lo que el otro conoce.

Si es todo tu propio código y no estás usando esto y constructores … lo cual es una buena idea por muchas razones, entonces puedes hacerlo así:

  var makeHorse = function () { var neigh = "neigh"; return { doTheNoise: function () { return neigh + " is all im saying" }, setNeigh: function (newNoise) { neigh = newNoise; } } }; var createSomething = function (fallThrough) { var constructor = function () {}; constructor.prototype = fallThrough; var instance = new constructor(); instance.someMethod = function () { console.log("aaaaa"); }; instance.callTheOther = function () { var theNoise = instance.doTheNoise(); console.log(theNoise); }; return instance; }; var firstHorse = makeHorse(); var secondHorse = makeHorse(); secondHorse.setNeigh("mooo"); var firstWrapper = createSomething(firstHorse); var secondWrapper = createSomething(secondHorse); var nothingWrapper = createSomething(); firstWrapper.someMethod(); firstWrapper.callTheOther(); console.log(firstWrapper.doTheNoise()); secondWrapper.someMethod(); secondWrapper.callTheOther(); console.log(secondWrapper.doTheNoise()); nothingWrapper.someMethod(); //this call fails as we dont have this method on the fall through object (which is undefined) console.log(nothingWrapper.doTheNoise()); 

Esto no funciona para mi caso de uso, ya que los chicos de extjs no solo han usado erróneamente ‘esto’ sino que también han construido un sistema de tipo de herencia completamente loco y clásico sobre el principio del uso de prototipos y ‘esto’.

Esta es la primera vez que uso prototipos / constructores y me sorprendió un poco que no puedas simplemente configurar el prototipo, también debes usar un constructor. Hay un campo mágico en los objetos (al menos en Firefox) llamado __proto que es básicamente el prototipo real. parece que el campo del prototipo real solo se usa en el momento de la construcción … ¡qué confuso!


Copiar métodos

Este método es probablemente más caro, pero me parece más elegante y también funcionará con el código que lo usa (por ejemplo, para que pueda usarlo para envolver objetos de la biblioteca). También funcionará en cosas escritas usando el estilo funcional / de cierre también. Lo acabo de ilustrar con this / constructors para mostrar que funciona con cosas como esa.

Aquí están los mods:

  //this is now a constructor var MakeHorse = function () { this.neigh = "neigh"; }; MakeHorse.prototype.doTheNoise = function () { return this.neigh + " is all im saying" }; MakeHorse.prototype.setNeigh = function (newNoise) { this.neigh = newNoise; }; var createSomething = function (fallThrough) { var instance = { someMethod : function () { console.log("aaaaa"); }, callTheOther : function () { //note this has had to change to directly call the fallThrough object var theNoise = fallThrough.doTheNoise(); console.log(theNoise); } }; //copy stuff over but not if it already exists for (var propertyName in fallThrough) if (!instance.hasOwnProperty(propertyName)) instance[propertyName] = fallThrough[propertyName]; return instance; }; var firstHorse = new MakeHorse(); var secondHorse = new MakeHorse(); secondHorse.setNeigh("mooo"); var firstWrapper = createSomething(firstHorse); var secondWrapper = createSomething(secondHorse); var nothingWrapper = createSomething(); firstWrapper.someMethod(); firstWrapper.callTheOther(); console.log(firstWrapper.doTheNoise()); secondWrapper.someMethod(); secondWrapper.callTheOther(); console.log(secondWrapper.doTheNoise()); nothingWrapper.someMethod(); //this call fails as we dont have this method on the fall through object (which is undefined) console.log(nothingWrapper.doTheNoise()); 

De hecho, estaba anticipando tener que usar bind en algún lugar, pero parece que no es necesario.

No que yo sepa, pero puede simularlo inicializando la función para null al principio y luego reemplazando la implementación más tarde.

 var foo = null; var bar = function() { alert(foo()); } // Appear to use foo before definition // ... foo = function() { return "ABC"; } /* Define the function */ bar(); /* Alert box pops up with "ABC" */ 

Este truco es similar a un truco de C # para implementar lambdas recursivas, como se describe aquí .

El único inconveniente es que si usa foo antes de definirlo, obtendrá un error al intentar llamar a null como si fuera una función, en lugar de un mensaje de error más descriptivo. Pero esperaría obtener algún mensaje de error para usar una función antes de que esté definida.