可以是吸气剂或函数的对象属性

时间:2018-09-18 21:57:01

标签: javascript

我正在编码一个可链接库,并且我希望API允许将链的一部分作为静态值(具有默认值)以及有时作为函数来调用,以便可以将参数传递给它们。

简化示例:

var obj = {};
var chainCache = [];

Reflect.defineProperty(obj, 'color', {
  get(){
    chainCache.push('red');
    return obj;
  }
})

Reflect.defineProperty(obj, 'background', {
  get(){
    chainCache.push('black');
    return obj;
  }
})

Reflect.defineProperty(obj, 'end', {
  value(){
    var value = chainCache.join(" ");
    chainCache.length = 0;
    return value;
  }
})

console.log( obj.color.background.end() ) // red black

这是一个非常简化的示例,实际上,我还想在上面的“ API”中包括一个功能,可以选择使用相同 color键,如下所示:

obj.color.background.end()          // current API (great)
obj.color('#FF0').background.end()  // optionally call "color" as function
obj.color().background.end()        // bad API, I do not want this

color可以同时称为功能属性,具体取决于调用方式吗?

2 个答案:

答案 0 :(得分:0)

我比预期的要认真地看待这个问题。随着Proxies的出现,这似乎是可能的。以您的示例为基础:

let chainCache = [];
let obj = {
    color: new Proxy(()=>{}, {
        get: (target, prop) => {
            chainCache.push("red");
            if(prop === "background") {
                chainCache.push("black");
                return { end: obj.end };
            }
        },
        apply: (target, prop, args) => {
            if(args.length > 0) {
                chainCache.push(args.pop());
            } else {
                throw new Error("color expects argument if called like function");
            }
            return { background: new Proxy(()=>{}, {
                get: (target,prop) => { chainCache.push("black"); return obj.end;}
            })};
        }
    }),
    end: () => {
        let value = chainCache.join(" ");
        chainCache = [];
        return value;
    }
};
console.log(obj.color.background.end());
console.log(obj.color("#FF0").background.end());
console.log(obj.color().background.end());

在调试控制台中,您将得到:

red black
#FF0 black
Error: color expects argument if called like function

从本质上讲,color是包装匿名箭头函数的代理,如果将color作为属性访问,则调用get()陷阱;如果将color作为函数访问,则调用apply()陷阱。这样就可以像您正在寻找的那样进行某种程度的元编程。

答案 1 :(得分:0)

您需要使obj为函数。

一个函数仅仅是一个对象,并且可以具有属性-obj.color必须返回一个具有属性(对于obj.color()的函数(对于obj.color.background)。

但是不,当访问getter时,您还不知道它是否将用于方法调用-obj.color()是属性访问 plus 函数调用。

var chainCache = [];
var obj = Object.defineProperties(function obj(...args) {
  chainCache.push(args);
  return obj;
}, {
  color: {
    get() {
      chainCache.push('color');
      return obj;
    }
  },
  background: {
    get() {
      chainCache.push('background');
      return obj;
    }
  },
  end: {
    value: function() {
      var res = chainCache.reduce((acc, val) =>
        Array.isArray(val)
          ? `${acc}(${val.join(',')})`
          : `${acc}.${val}`
      , "obj");
      chainCache.length = 0;
      return res;
    }
  }
})