在函数之间传递元数据

时间:2016-11-09 23:12:40

标签: javascript node.js

我使用Node.js创建了一个API,我不想更改API,也不想在函数中添加额外的参数。但是,库中的内部代码现在需要在内部API方法和外部方法之间发送一些元数据。

有没有办法在JS中以某种方式在函数之间传递(元)数据而不涉及参数/参数?

TL; DR,为了JS API的目的,在函数之间传递元数据非常有用,它不应该改变签名。

(一个技巧是如果每次调用函数时都会创建它,你可以将数据分配给函数对象本身,但在这种情况下不是这样(每次调用时都不会创建函数)。)

我目前正在使用的技巧 - 而不是一个好的 - 在API中使用了一个options {}对象。我在该对象对象“__preParsed”中传递一个隐藏属性。用户将像往常一样使用该对象对象,在幕后我将它用于一些他们不需要了解的簿记内容。

好的,这里是代码:

// public API

   beforeEach.cb = function (desc, opts, fn) {
        const _args = pragmatik.parse(arguments, rules.hookSignature);
        _args[ 1 ].cb = true;
        return beforeEach.apply(ctx, _args);
   };


   beforeEach = function (desc, opts, aBeforeEach) {

        handleSetupComplete(zuite);

        const _args = pragmatik.parse(arguments, rules.hookSignature);

        const obj = {        //have to do this until destructuring works
          desc: _args[ 0 ],
          opts: _args[ 1 ],
          fn: _args[ 2 ]
        };

        handleBadOptionsForEachHook(obj.opts, zuite);

        return 'there is more code but I omitted it';
    };

你可以看到第一个方法调用第二个方法,或者第二个方法可以直接调用,两者都是公共API。

我们需要在两个调用中解析参数,但作为优化,如果第二个方法被第一个方法调用而不是直接调用,我们不应该再次解析它们。

我将暂时使用的解决方案是:

       beforeEach.cb = function (desc, opts, fn) {
            const _args = pragmatik.parse(arguments, rules.hookSignature);
            _args[ 1 ].cb = true;
            _args[ 1 ].__preParsed = true;
            return beforeEach.apply(ctx, _args);
       };

opts选项对象是公共的,但用户不会知道__preParsed属性。内部API将。

这个问题是用户可以在没有选项对象的情况下直接调用公共API,并且因为签名非常多,所以我真的不知道,直到我用我的解析引擎解析它,arg如果有对象就是对象!

2 个答案:

答案 0 :(得分:2)

您可以通过使用this调用函数来滥用Function.prototype.call对象来携带非参数元数据:

function inner (arg1, arg2) {
  console.log('inner called with', arg1, arg2)
  console.log('inner metadata', this._meta_count)
}

inner.call({_meta_count: 17}, 'ARG ONE', 'ARG TWO')
inner.call({_meta_count: 18}, 'ARG ONE B', 'ARG TWO B')

答案 1 :(得分:1)

您可以在结尾添加一个新的未记录的参数。 JavaScript不关心,以前的调用仍然有效,为什么这对你来说是一个问题?

如果您正在检查参数计数和抛出错误,您可以预期隐藏参数是具有魔术属性的对象,如果不是,则抛出错误。

function go(a, b, c, _internal) {
  if (_internal && ! _internal.hasOwnProperty('_magic')) {
    throw new Error('invalid internal parameter passed');
  }
}

你可以得到更多的偏执并将魔法属性存储为Symbol,然后调用者无法意外通过它,他们必须采取恶意行为。

function go(a, b, c, _internal) {
  if (_internal && !_internal.hasOwnProperty(go.internalParamProp)) {
    throw new Error('invalid internal parameter passed');
  }
  console.log("Internal param", _internal && _internal[go.internalParamProp])
}
// Symbol for the magic property name to avoid accidental passing of internal param
go.internalParamProp = Symbol('');

// Passing the internal param
// Uses JS syntax that is not yet supported in some browsers
// If it's a concern, use or var obj={}; obj[go.internalParamProp] = 45
go(1, 2, 3, {
  [go.internalParamProp]: 45
})

// Regular call
go(1, 2, 3)

// Invalid call
go(1, 2, 3, 4)