Does Javascript have something like a Ruby method_missing function?

In Ruby, I think you can call a method that has not been defined, and still capture the name of the called method and process that method at runtime.

Can Javascript do the same?

+48
javascript ruby metaprogramming
Mar 19 '12 at 23:50
source share
8 answers

The ruby ​​function you explain is called "method_missing" http://rubylearning.com/satishtalim/ruby_method_missing.htm .

This is a new feature that is only present in some browsers, such as Firefox (in the Javascript engine for spider-spider). In SpiderMonkey, it's called "__noSuchMethod__" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod

Read this article from Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ for more details on the upcoming implementation.

+29
Mar 20 2018-12-12T00:
source share

method_missing is not suitable for JavaScript for the same reason that it does not exist in Python: in both languages, methods are simply attributes that are functions; and objects often have public attributes that are not callable. Contrast with Ruby, where the public interface of an object is a 100% method.

What you need in JavaScript is a hook to catch access to missing attributes, regardless of whether they are methods or not. Python has this: see __getattr__ special method.

Mozilla's __ noSuchMethod__ proposal introduced yet another inconsistency in the language in which they are pierced.

Forward, JavaScript is a Proxy server mechanism (also in ECMAscript Harmony ), which is closer to the Python protocol for setting access to attributes than to Ruby method_missing .

+44
Jan 29 '13 at 14:01
source share

Not at the moment. There is an offer for ECMAScript Harmony called proxies that implements a similar (in fact, much more powerful) function, but ECMAScript Harmony does not come out and probably will not be for a couple of years.

+4
Mar 20 2018-12-12T00:
source share

I created a library for javascript that allows you to use method_missing in javascript: https://github.com/ramadis/unmiss

It uses ES6 Proxies to work. Here is an example using ES6 class inheritance. However, you can also use decorators to achieve the same results.

 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 
+2
Sep 02 '17 at 20:51 on
source share

No, there is no metaprogramming in javascript, similar to the method_missing ruby. The interpreter simply causes an error that the calling code can catch, but cannot be detected by the object being accessed. There are some answers to the definition of functions at runtime, but they are not the same thing. You can metaprogram a lot, modify specific instances of objects, define functions, and perform functional functions such as memories and decorators. But there is no dynamic metaprogramming of missing functions, like in ruby ​​or python.

+1
Mar 20 2018-12-12T00: 00Z
source share

I came to this question because I was looking for a way to fail on another object if the method was not present on the first object. It is not as flexible as what you ask - for example, if a method is missing, then it will fail.

I was thinking of doing this for the small library that I have, which helps to customize extjs objects in a way to make them more verified. I had separate calls to actually get objects to interact with and thought that this might be a good way to connect these calls, effectively returning an extended type

I can imagine two ways to do this:

Prototypes

You can do this using prototypes, as the material falls into the prototype if it is not on the object itself. It doesn't seem to work if the set of functions you want to use to use this keyword is obviously your object does not know or does not care about things that the other knows about.

If all of its own code and you don’t use this and the constructors ... which is a good idea for many reasons, you can do it like this:

  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()); 

This does not work for my use case, as the guys from extjs not only mistakenly used 'this', they also created a whole crazy system of the classical type of inheritance, using prototypes and 'this'.

This is the first time I've used prototypes / constructors, and I was a little puzzled that you cannot just install the prototype - you will also have to use the constructor. There is a magic field in objects (at least in firefox) that calls __proto, which is basically a real prototype. it seems that the actual prototype field is only used during construction ... how confusing!




Copy methods

This method is probably more expensive, but seems more elegant to me, and will also work with code using this (for example, so that you can use it to wrap around library objects). In addition, he will work with materials written using a functional / closing style. I just illustrated this with these / constructors to show that it works with such things.

Here are the 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()); 

I really expected to use bind somewhere, but it doesn't seem to be necessary.

+1
Sep 16 '14 at 11:10
source share

You can use the proxy class .

 var myObj = { someAttr: 'foo' }; var p = new Proxy(myObj, { get: function (target, methodOrAttributeName) { // target is the first argument passed into new Proxy, aka. target is myObj // First give the target a chance to handle it if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) { return target[methodOrAttributeName]; } // If the target did not have the method/attribute return whatever we want // Explicitly handle certain cases if (methodOrAttributeName === 'specialPants') { return 'trousers'; } // return our generic method_missing function return function () { // Use the special "arguments" object to access a variable number arguments return 'For show, myObj.someAttr="' + target.someAttr + '" and "' + methodOrAttributeName + '" called with: [' + Array.prototype.slice.call(arguments).join(',') + ']'; } } }); console.log(p.specialPants); // outputs: trousers console.log(p.unknownMethod('hi', 'bye', 'ok')); // outputs: // For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok] 

ABOUT

You would use p instead of myObj .

You have to be careful with get because it intercepts all requests for p attributes. Thus, p.specialPants() will result in an error because specialPants returns a string, not a function.

What really happens with unknownMethod is equivalent to the following:

 var unk = p.unkownMethod; unk('hi', 'bye', 'ok'); 

This works because functions are objects in JavaScript.

Bonus

If you know the expected number of arguments, you can declare them as normal in the return function.
eg:

 ... get: function (target, name) { return function(expectedArg1, expectedArg2) { ... 
0
Sep 26 '19 at 9:01
source share

As far as I know, but you can simulate it by first initializing the function to null and then replacing the implementation later.

 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" */ 

This trick is similar to the C # trick for implementing recursive lambdas, as described here .

The only drawback is that if you use foo before defining it, you will get an error message to try to call null , as if it were a function, and not a more descriptive error message. But you expect to receive an error message for using the function before defining it.

-one
Mar 19 '12 at 23:53
source share



All Articles