標題有點說明了一切。在 JavaScript 中,您如何將變數注入您無法控制的函式的內部范圍(例如回呼)?這通常在各種 JavaScript 框架中完成,其中 Jest 為您提供describe、it、beforeAll等,所有這些都在 Jest 不明確了解的回呼主體中。Cucumber 使用共享World實體更干凈地做到了這一點,并且還提供了為該物件提供自定義建構式的控制元件,但是如果我想logger使用我的庫將物件添加到任何東西的執行范圍,那么將它添加到的唯一答案是global,或者有沒有辦法將值保持在被呼叫函式及其回呼的范圍內?
編輯:這是我認為笨重的解決方案,但它在技術上實作了目標。如果這是公認的解決方案,我會繼續前進,但我認為必須有一種更復雜/更干凈的方法來做到這一點。
function a(opts, callback) {
Object.assign(global, opts);
const assignedKeys = Object.keys(opts).filter(k => Object.prototype.hasOwnProperty.call(global, k));
for(const k in opts) {
console.log('%s: %s', k, opts[k]); // val: 5
callback(); // Can I see it? true
}
console.log('Before clean-up', assignedKeys.map(k => `${k}: ${global[k]}`).join(', '));
// Before clean-up val: 5
for(const k in opts) {
delete global[k];
}
console.log('After clean-up', assignedKeys.map(k => `${k}: ${global[k]}`).join(', '));
// After clean-up val: undefined
}
function b() {
console.log('Can I see it?', !!val);
// Can I see it? true
}
a({ val: 5 }, b);
uj5u.com熱心網友回復:
可能不是最優雅的,但您可以使用建構式創建toString()一個函式并注入變數。Function
這是您示例的簡化版本:
function inject(cb, hw = "Hello, world!") {
const injection = `const hw = "${hw}";`;
const fn = new Function(`${injection} return (${cb.toString()})();`);
const result = fn();
if(result)
console.log(result);
// cb(); <-- error: hw is undefined
}
inject(() => {
console.log(hw);
});
inject(function() {
console.log(hw);
}, "Hello, StackOverflow!");
inject(function test() {
console.log(hw);
return 5;
});
uj5u.com熱心網友回復:
是的,使用全域變數是這方面的標準做法。無法更改您無法控制的函式的范圍,不可能將新的區域變數“注入”到其中。您唯一能做的就是將變數放在共享范圍內(并假設函式不會隱藏它們),這通常是全域范圍。
像 React 或 Jest 這樣的框架擺脫了這種做法,因為它們是為其撰寫所有代碼的全域框架,因此開發人員了解此功能并且不會被“神奇”變數所迷惑——而且它只是極少數,嗯——已知變數。盡管如此,工具仍然需要被告知這些全域變數。這是一種折衷,但有時值得,因為它會導致更簡潔的代碼。
請注意,與您的a函式不同,此類全域變數不是動態的,而是靜態宣告的,它們不關心沖突和清理。如果您使用這樣的框架,您將預先知道有哪些全域變數,并且不會撰寫干擾它們的代碼。
如果您真的想動態地將任意值“注入”到被呼叫函式中,有一種標準技術:使用引數!您呼叫的函式需要宣告引數才能使用它們,但這是正確的干凈解決方案,并且確實會將變數范圍限定在您想要的位置。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/418261.html
標籤:
