Javascript — сделать функцию в объекте глобальной

#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);
    }
}