#javascript #function #global
Вопрос:
Допустим, у меня есть объект obj
с функцией f1
, которая принимает два параметра a
и b
. Функция вызывается следующим образом:
obj.f1(a,b);
Теперь я хочу сделать f1
доступным без звонков obj
следующее:
f1(a,b);
Возможно ли это? Если да, то как я могу этого добиться?
Изменить: Если да, есть ли способ сделать все функции в объекте глобальными, не зная конкретных функций?
Комментарии:
1.
const f1 = obj.f1
а потом позвонить ему позже, используяf1(a, b)
? это предполагает, чтоf1
это не зависит отthis
2. @NickParsons Звучит неплохо. Есть ли способ сделать все функции в объекте глобальными, не зная конкретных функций?
3. да и нет. как правило, это не очень хорошая идея, и мне любопытно, почему вы хотите это сделать. … тем не менее, поскольку не существует «истинного» глобального, а только
global
window
объекты и зависят от вашего env, вы можете просто выполнить цикл над своим объектом и скопировать все записи функции типа вglobal
илиwindow
Ответ №1:
Хотя это не лучшая идея для этого, вы можете добавить свойства к глобальному window
объекту (если вы запускаете его в браузере, если вы используете узел, то можете обратиться к global
— здесь я использую globalThis
, чтобы это работало в обеих средах), а затем вызвать их без необходимости префикса obj
. Добавление свойств в window
(т. Е. globalThis) обычно не является хорошей идеей, потому что в конечном итоге вы можете перезаписать уже существующие свойства в окне. С учетом сказанного, вот как вы можете это сделать:
const obj = {x: 1, y: function() {
console.log("hello");
}}
Object.entries(obj).forEach(([key, val]) => {
if(typeof val === "function")
globalThis[key] = val;
});
y();
Имейте в виду, что если методы вашего объекта ссылаются на this
, то при вызове вашего метода this
он будет привязан к глобальному объекту (т. Е.: window
), или, если вы выполняете это в строгом режиме, то так и будет undefined
.
Вот несколько примеров некоторых из упомянутых выше предостережений:
Изменение ранее существовавших свойств: Объект окна имеет некоторые ранее существовавшие свойства. Одним из таких свойств является name
свойство, которое JS принуждает быть строкой. Это означает, что если у вас есть метод, вызываемый name
в вашем объекте, он будет преобразован в строку, как только он будет добавлен в window
:
const obj = {x: 1, name: function() {
console.log("hello");
}}
Object.entries(obj).forEach(([key, val]) => {
if(typeof val === "function")
globalThis[key] = val;
});
console.log(typeof name); // string
name(); // Crash: "Uncaught TypeError: name is not a function"
Потеря this
внутреннего вашего метода: Если ваш метод ссылается на this
, то вы можете ожидать, что ваш метод больше не будет работать, так как он теряет свою this
привязку:
const obj = {x: 1, y: function() {
console.log(this.x); // undefined (as `this` now refers to window)
}, z: function() {
'use strict';
console.log(this.x); // Crashes, because this is undefined when in strict-mode
}}
Object.entries(obj).forEach(([key, val]) => {
if(typeof val === "function")
globalThis[key] = val;
});
y(); // undefined
z(); // "Uncaught TypeError: Cannot read property 'x' of undefined"
Чтобы помочь устранить вышеуказанные проблемы this
, вы можете рассмотреть возможность привязки вашего метода при назначении его окну, чтобы его контекст был предопределен:
const obj = {x: 1, y: function() {
console.log(this.x); // this is bound to `obj` (via the .bind() method)
}, z: function() {
'use strict';
console.log(this.x); // this is bound to `obj` (via the .bind() method)
}}
Object.entries(obj).forEach(([key, val]) => {
if(typeof val === "function")
globalThis[key] = val.bind(obj);
});
y(); // 1
z(); // 1
Ответ №2:
Вы можете разрушить свойства объекта, как это:
const someObject = {
f1: (a, b) => a b,
f2: (a, b) => a * b,
defaultParams: [1, 1],
}
const {f1, f2, defaultParams} = someObject;
console.log(f1(defaultParams[0], 15) * f2(...defaultParams));
Или извлеките записи из объекта и назначьте их глобальной области (здесь window
, что не рекомендуется).
const someObject = {
f1: (a, b) => a b,
f2: (a, b) => a * b,
defaultParams: [1, 1],
}
Object.entries(someObject).forEach( ([key, entry]) => window[key] = entry );
console.log(f1(defaultParams[0], 15) * f2(...defaultParams));
Вы можете создать анонимную область. В следующем фрагменте this
следует привязать к объекту, чтобы методы были обернуты с помощью [function].apply
. Кроме того, используется альтернативный способ деструктурирования.
// this syntax creates an anonymous scope
// so f1/f2/defaultParams are *not* window properties
(() => {
const someObject = {
b: 42,
f1(a) { return a this.b; },
f2(a) { return a * this.b; },
defaultParams: [1, 1],
}
// another way of destructuring ...
const [f1, f2, defaultParams] = [
(...params) => someObject.f1.apply(someObject, params),
(...params) => someObject.f2.apply(someObject, params),
someObject.defaultParams,
];
// or use the shorter *bind* syntax, e.g.
const f3 = someObject.f1.bind(someObject);
console.log(f1(defaultParams[0]), f2(2));
console.log(f3(defaultParams[0]));
// still NOT advisable, but coming to think of it ...
window.f2FromWithin = someObject.f2.bind(someObject);
})();
console.log(f2FromWithin(42));
Ответ №3:
Для этого используются две «устаревшие» команды: with
и eval
🙂
// assuming this is in the node.js
with (obj) {
for (i in obj) {
eval('global.' i '=' i);
}
}