Javascript: Function Chain

solution: no. you cannot do this. chain commands with && and do with it.

tl; dr: in random.function("blah").check() , how to make it ignore check() if function("blah") returns false? Or is it possible?

Background:

Good, so I'm terrible in code. But I'm trying to drag out, coding things that would make my life easier. And my insignificant, I mean microscopically. Thus, basically, my whole project is based on objects and plugins. (plugins are additional .js files that contain an object. For example, afk.js looks something like this:

 global.afk = function(){}; afk.check = function(){ ... }; 

etc. etc. And loading this js file, I get access to the afk object and the whole function in it. Probably inefficient, but it works, and it finds out which functions make it easier.

Back to the scroll bit. Since I do not know which plugins are loaded, some files with a common .js core have the following conditional statements: if (plugin.has("afk")) { afk.check(); }; if (plugin.has("afk")) { afk.check(); }; However, I got bored and did plugin.has() to return the actual object instead of "true", so I could do:

 plugin.has("afk").check(); 

works as expected. If there is no afk plugin that throws an obvious error: "false has no method check".

And so it happened. Any ideas? Also, if you have any problems with anything, let me know. I know that I do a lot of things wrong / inefficiently, and I am pleased to fix them when I understand this.

+7
source share
8 answers

The returned object must have this function, otherwise you will receive an error message. You can make the base type of an object that always returns. Then, when you return it, it has an empty function and does not generate an error.

Something like:

 var baseObj = function(){ this.afk = function(){ return this; } this.check = function(){ return false; } }; var advObj = new baseObj(); advObj.afk = function(){ // extended func return new baseObj(); } var a = new advObj(); a.afk("test").check(); 
+1
source

So jQuery does it something like this:

$(plugin) returns the collection as an object
.has("afk") → filters the internal collection and returns the .check() collection → the action performed in this collection

So make a small example:

 function Wrapper(ele) { // make our collection this.coll = [ ele ]; // function to filter this.has = function(filter) { this.coll = this.coll.filter(function(e) { return e === filter; }); // we return ourself for chaining return this; }; // function to execute on ourself this.check = function() { // returns actual value return this.coll.length; }; } var $ = function(ele) { // wrapper around the `new` syntax return new Wrapper(ele); }; console.log($('jan').has('jan').check()); // gives 1 console.log($('pietje').has('jan').check()); // gives 0 

Cool, now you can expand your Wrapper object from external files by expanding the prototype:

 Wrapper.prototype.hasNot = function(filter) { /* do magic */ return this; } 
+1
source

In current ECMAScript specifications, including .check() in a no-op (and any other method that may exist on a non-existent plugin) is not possible because you cannot, because you found access to the undefined undefined properties available on the port.

The proposed "Direct Proxies" ECMAScript API seems to solve this, but it is not yet standardized. I also suspect that it is not very efficient to proxy your code this way, since you (AIUI) must force your .has() function to return a proxy server object, which then has to do the real work for each "missed" function call. It would be much better IMHO just to make sure that conditional code never runs at all.

So, apart from the method proposed by && , all I can offer is:

 plugin.if("afk", function() { // put conditional code here }); 
+1
source

A short and dirty way to do this job would be to use the && Operator.

 var x = {}; x.afk && x.afk(); x.afk = function () { console.log("I exist!"); }; x.afk && x.afk(); 

Not an optimal solution for a wide range.

0
source

It will not work in all browsers, but I think you could create a dummy class that uses __noSuchMethod__ to always return itself, and not throw an error when calling a nonexistent method. See this question .

I do not know in which browsers this will work, and my overall impression is "a bit."

0
source

Oh, hi. Node-proxy looks promising. I really don't know anything about this, but it seems like this should allow you to do just such things.

0
source

In fact, you already solved the problem yourself, at least almost:

This is for any number of functions that perform any number of things. I was thinking of switching plugin.has() to plugin.has("afk","check"); or something similar, so instead of a chain of functions, it's just one function. But passing variables to the validation function will be difficult.

Well, there are two ways to do this:

 plugin_with_afk.has("afk","check").check(100); // "check" twice plugin_with_afk.has("afk","check")(100); // "check" not twice 

The first way is actually quite simple: just return this if the plugin has "afk" and otherwise returns an object that has a no-op check method:

 Plugin.prototype.has = function(str, member){ if(this.things.indexOf(str) > -1) { return this; } else { var tmp = {} tmp[member] = function(){} return tmp; } } plugin_with_afk.has("afk","check").check(1); // has afk, check is there plugin_without_afk.has("afk","check").check(2); // has no afk, check is no-op plugin_without_afk.has("nope","check").check(3); // has nope, check is there 

This also has the great advantage that you do not need to use any kind of shell functions, etc. However, you need to specify the function used twice, which will lead to a ReferenceError if you accidentally used a different name:

 plugin_with_afk.has("afk","check").test(1); // oh oh 

So what can you do against this? Create a simple function wrapper:

 PluginWithFuncRet.prototype.has = function(str,member){ var self = this; if(this.things.indexOf(str) > -1) { return function(){ return self[member].apply(self, arguments); } } else { return function(){}; } } plugin_with_afk.has("afk","check")(4); // calls check() plugin_without_afk.has("afk","check")(5);// no-op 

What is it. Note that you really have to rename has to use_if or something similar, as it now does a lot of things more than actually checks to see if there is a component.

Full code (demo)

 var PluginBase = function(name, things){ this.name = name; this.things = things; } /// First variant var Plugin = function() { this.constructor.apply(this, arguments); } Plugin.prototype.constructor = PluginBase; Plugin.prototype.has = function(str,member){ if(this.things.indexOf(str) > -1) { return this; } else { var tmp = {} tmp[member] = function(){} return tmp; } } var plugin_with_afk = new Plugin("with afk", ["afk"]); plugin_with_afk.check = function(val){ console.log("hi", val, this.name); }; var plugin_without_afk = new Plugin("w/o afk", ["nope"]); plugin_without_afk.check = function(val){ console.log("nope", val, this.name); } /// First variant demo plugin_with_afk.has("afk","check").check(1) plugin_without_afk.has("afk","check").check(2) plugin_without_afk.has("nope","check").check(3) /// Alternative var PluginWithFuncRet = function(){ this.constructor.apply(this, arguments); } PluginWithFuncRet.prototype.constructor = PluginBase; PluginWithFuncRet.prototype.has = function(str,member){ var self = this; if(this.things.indexOf(str) > -1) { return function(){ return self[member].apply(self,arguments); } } else { return function(){} } } plugin_with_afk = new PluginWithFuncRet("with afk",["afk"]); plugin_with_afk.check = function(val){ console.log("Hi",val,this.name); } plugin_without_afk = new PluginWithFuncRet("w/o afk",["nope"]); plugin_without_afk.check = function(val){ console.log("Nope",val,this.name); } /// Alternative demo plugin_with_afk.has("afk","check")(4); plugin_without_afk.has("afk","check")(5); plugin_without_afk.has("nope","check")(6); 

Result:

  hi 1 with afk
 nope 3 w / o afk
 Hi 4 with afk
 Nope 6 w / o afk
0
source

So this is what I came across and ended up using it eventually.
Instead of creating a dummy wrapper, I decided to load all the plugins into the main shell. So, now afk is plg.afk, since using all the other plugins. This allowed me to write this shell:

 global.& = function(a,b) { var x,y,z;if (!a) return false; //if nothing, return false. if (a.indexOf(".") < 0) { //if value has no "." if (plg["data"][a]) { x = ["data",a]; } //use data function if exists else { x = ["basic",a]; } //else assume it a basic function } else { //or if it does contain "." (such as my example, afk.check) x = a.split(".") //define the plugin, and the function as an array. } y = x[0],z = x[1]; //define the plugin,function as variables. if (!plg[y]) { return false; } //return if plugin doesn't exist. if (!plg[y][z]) { return false; } //return if function doesn't exist. if (!b) { plg[y][z](); } //if no variable, call raw function return plg[y]z[](b); //return function, passing an optional variable. } 

So it works! I can call $ ("afk.check"); And this is essentially:

 if (plugin.has("afk") && afk.hasOwnProperty("check")) { afk.check(); }; 

: D

And I can pass variables. and use the shortcut for the main functions.

For example, if I call $("boot"); , then it checks the data for the load function, and when it does not find it, returns to basic.boot () ;, and calls the correct function. And I can call data functions and pass variables, for example, in the case of saving data, $("save",data);

Feel free to let me know if this is a stupid idea! But for now, this works for me <3

0
source

All Articles