Javascript - 使对象中的函数成为全局函数

Javascript - make function in object global

假设我有一个对象 obj,其函数 f1 接受两个参数 ab。函数调用如下:

obj.f1(a,b);

现在我想在不调用 obj 的情况下使 f1 可访问,如下所示:

f1(a,b);

这可能吗?如果可以,我该如何实现?

编辑:如果是,有没有办法在不知道具体函数的情况下,使对象中的所有函数成为全局函数?

虽然这样做不是最好的主意,但您可以向全局 window 对象添加属性(如果 运行 在浏览器中使用 node,那么您可以参考 global - 这里我使用 globalThis 所以这在两种环境下都有效),然后调用它们而不需要前缀 obj。向 window 添加属性(即:globalThis)通常不是一个好主意,因为您最终可能会覆盖 window 上预先存在的属性。话虽如此,您可以按照以下方式进行操作:

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.

以下是上述一些注意事项的一些示例:

修改预先存在的属性:window 对象有一些预先存在的属性。其中一个 属性 是 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 的上述问题,您可以考虑在将方法分配给 window 时绑定您的方法,以便预定义其上下文:

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

您可以 destructure 像这样的对象的属性:

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,即not advisable)。

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

这是使用两个 'deprecated' 命令:witheval :)

// assuming this is in the node.js
with (obj) {
    for (i in obj) {
        eval('global.'+i+'='+i);
    }
}