Javascript:功能链接

时间:2013-04-15 17:28:38

标签: javascript node.js function object

解决方案:不。你不能这样做。带&&的链命令并完成它。

tl; dr:在random.function("blah").check()中,如果check()返回false,如何忽略function("blah")?或者这甚至可能吗?

背景:

好的,所以我对代码很可怕。但是我试图通过编码使我的生活变得轻松的事情来拖延。而我的勉强,我的意思是显微镜。所以基本上,我的整个项目都是基于对象和插件。 (插件是包含对象的附加.js文件。例如,afk.js看起来像这样:

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

等等。通过加载该js文件,我可以访问afk对象及其中的所有功能。可能效率不高,但它有效,它可以确定哪些功能更容易做到。

回到拖延位。因为我不知道加载了哪些插件,在一些共享核心.js文件中,有以下条件语句:if (plugin.has("afk")) { afk.check(); };然而,我感到无聊并使plugin.has()返回实际对象而不是'是',所以我可以这样做:

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

按预期工作。除非没有afk插件,否则会抛出“false not no method check”的明显错误。

就是这样。有任何想法吗?此外,如果您有任何疑虑,请告诉我。我知道我做了很多错误/效率低下的事情,当我想出来时修复它们很好。

8 个答案:

答案 0 :(得分:1)

返回的对象应具有该功能,否则会出错。你可以做的是创建一个基本的Object类型,它总是被返回。与返回时相比,它具有空函数,不会产生错误。

类似的东西:

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 :(得分:1)

所以jQuery有点像这样:

$(plugin) - >返回像对象一样的集合 .has("afk") - >过滤内部集合,并返回集合
.check() - >对此集合执行的操作

让我们举一个小例子:

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

很酷的是你现在可以通过扩展原型来扩展你的Wrapper对象来自外部文件:

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

答案 2 :(得分:1)

在当前的ECMAScript规范中,将.check()转换为无操作(以及可能存在于不存在的插件上的任何其他方法)是不可能的,因为您无法找到未定义的undefined属性对象。

建议的"Direct Proxies" ECMAScript API似乎可以解决这个问题,但它还没有标准化。我还怀疑以这种方式代理你的代码并不是非常有效,因为你会(AIUI)必须让你的.has()函数返回一个陷阱代理对象,然后必须为每个“错过的”函数调用做真正的工作。恕我直言,只需确保条件码永远不会运行。

所以,除了其他地方提出的&&方法之外,我能提供的就是:

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

答案 3 :(得分:0)

简单而肮脏的方法是使用&&和操作

var x = {};

x.afk && x.afk();

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

x.afk && x.afk();

不是最佳的广泛解决方案。

答案 4 :(得分:0)

它不适用于所有浏览器,但我认为您可以创建一个虚拟类,使用__noSuchMethod__始终返回自身,而不是在调用不存在的方法时抛出错误。请参阅this question

我不知道这会使用什么浏览器,我的总体印象是“不多”。

答案 5 :(得分:0)

哦,你好。 Node-proxy看起来很有希望。我实际上并不了解它,但听起来它应该让你做到这一点。

答案 6 :(得分:0)

实际上你已经解决了这个问题,至少差不多:

  

这适用于任何数量的功能。我正在考虑将plugin.has()切换为plugin.has("afk","check");或类似的东西,因此它不是链接函数,而是在一个函数中。    但是将变量传递给check函数会变得棘手。

嗯,基本上有两种方法:

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

第一种方式实际上相当简单:如果插件具有“afk”,则返回this,否则返回具有无操作方法的对象check

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

这也有很大的优势,你不需要使用任何函数包装器等。但是,您必须指定两次使用的函数,如果您不小心使用了其他名称,则会导致ReferenceError

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

那么你能对此做些什么呢?创建一个简单的函数包装器:

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

就是这样。请注意,您实际上应该将has重命名为use_if或类似的东西,因为它现在做的事情比实际检查组件是否存在更多。

完整代码(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);

结果:

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

答案 7 :(得分:0)

所以这就是我提出来的,最终最终使用了。
除了创建一个虚拟包装器之外,我决定加载所有的 插入主包装器。所以现在,afk是plg.afk,和
一样 所有其他插件。这让我写了这个包装器:

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's 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.
}

所以这个有效!我可以打电话给$(“afk.check”); 它本质上是这样的:

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

:d

我可以传递变量。并使用基本功能的快捷方式。

例如,如果我调用$("boot");,那么它会检查数据以获取启动函数,当它找不到启动函数时,将恢复为basic.boot();,并调用正确的函数。我可以调用数据函数并传递变量,例如在保存数据$("save",data);

的情况下

如果这是一个愚蠢的想法,请随时告诉我! 但到目前为止,它对我有用&lt; 3