2016-11-09 174 views
0

我使用Node.js創建了一個API,我不想讓API更改,也不想向函數添加額外的參數。但是,庫中的內部代碼現在需要在內部API方法和外部方法之間發送一些元數據。在函數之間傳遞元數據

有沒有辦法通過某種方式JS不涉及參數/參數的函數之間(元)數據?

TL; DR,它會傳遞函數之間的元數據API的JS的目的,是不應該改變的簽名真的很有用。 (一個技巧是如果每次調用函數時都創建函數,則可以將數據分配到函數對象本身,但在這種情況下不是這樣(函數在每次調用時都不會創建)。)

我目前使用的技巧 - 這是不是一個很好的 - 有API中使用{}對象的選項。我在該對象對象「__preParsed」中傳遞隱藏屬性。用戶將像通常那樣使用該對象對象,在幕後我使用它來記錄一些他們不需要知道的事情。

確定這裏是代碼:

//公共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

你可以濫用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,那麼調用者可能不是偶然的傳遞,他們將不得不nefariously作用。

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個變量而不是3個變量,那麼我會在第4個變量中選擇錯誤的變量? :)你可以看到各種各樣的潛在問題。 –

+0

我編輯了原始答案,我當前的解決方案取決於API中已經具有在函數之間傳遞的選項對象的API。但這不是一個通用的解決方案,因爲並不是所有的API都有一個對象對象被傳遞,儘管如果你向你的API添加一個選項obj,它可能會工作! –

+1

我認爲任何答案都不是100%。彼得的回答並不是傻瓜。兩者仍然允許調用者傳遞內部數據,但使其不太可能。我更喜歡我的,因爲如果你的函數依賴於'this',並且你可以不用'call'或'apply'來調用它,它仍然可以工作 –