2016-11-09 3 views
0

Я создал API с Node.js, и я не хочу, чтобы API менялся, и я не хочу добавлять дополнительные параметры к функции. Тем не менее, внутренний код в библиотеке должен теперь отправлять некоторые метаданные между внутренним методом API и внешним способом.Передача метаданных между функциями

Есть ли способ передавать (мета) данные между функциями как-то в JS, которые не включают параметры/аргументы?

TL; DR, было бы очень полезно передавать метаданные между функциями для целей JS API, которые не должны изменять подписи.

(Один трюк, если функция создается каждый раз, когда она вызывается, вы можете назначать данные непосредственно на объект функции, но это не так в этом случае (функция не создается каждый раз, когда она вызывается).)

трюк, который я использую в настоящее время, - и это не хороший - в API используется объект {}. Я передаю скрытое свойство в объекте объектов «__preParsed». Пользователь будет использовать объект объектов, как обычно, за кулисами я использую его для некоторых предметов бухгалтерского учета, о которых им не нужно знать.

Ok вот код:

// публичный 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'; 
    }; 

, как вы можете видеть, что первый метод вызывает второй, или второй можно назвать сразу, как публичные интерфейсы.

Нам нужно проанализировать аргументы в обоих вызовах, но в качестве оптимизации нам не нужно будет разбирать их второй раз, если второй метод был вызван первым, а не напрямую.

Решение, которое я буду использовать на данный момент является:

 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 напрямую без объекта options, а так как подпись очень много varargs, то я действительно не знаю, пока не разобрал его с моим синтаксическим анализатором, который arg, если какой-либо объект объектов!

ответ

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') 
+0

Действительно хороший, до тех пор, пока функция уже не использовать 'this' –

+0

да, к сожалению, уже есть контекст, хотя я мог бы просто добавить скрытые свойства этой связи проблема это, я должен был бы установить и затем отключить свойство, так как это метод в этом контексте, а значение свойства относится только к времени жизни вызова метода ... Лучше передать его как параметр. –

+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)

+0

Большая проблема, потому что тогда мой код может подумать, что дополнительный параметр поступает от пользователя, а не из моей библиотеки, а затем выкидывает ошибку, говоря, что пользователь неправильно использовал lib. Что делать, если пользователь прошел в 4 vars вместо 3, а затем я забираю неправильный var для 4-го? :) всевозможные потенциальные проблемы, как вы можете видеть. –

+0

Я отредактировал оригинальный ответ, мое текущее решение зависит от API, уже имеющего объект опций, переданный между функциями API. Но это не общее решение, потому что не все API-интерфейсы имеют объект-объект, который передается вместе, хотя в целом он может работать, если вы добавите опции obj в свои API-интерфейсы! –

+1

Я думаю, что любой ответ будет взломом, который не на 100%. Ответ Питера не является доказательством дурака. Оба по-прежнему позволяют вызывающему абоненту передавать внутренние данные, но делают его менее вероятным. Я предпочитаю мой, потому что он все еще работает, если ваша функция полагается на 'this', и вы можете называть его без' call' или 'apply' –

Смежные вопросы