从根本上说,本地引用全球范围本身是个坏主意吗?

问题描述

如果这是一个愚蠢的问题,请原谅我的无知或偏执狂,但我似乎无法在这种特定情况下找到任何东西(这使我认为也许大多数人都知道可以避免这种情况或有更好的方法来应对这个)。

这是前提:我不知道我的代码是否一定总是在浏览器中运行,因此,我不知道我是否可以访问window(具体来说是该名称),或者在我的代码可能会遇到的任何环境中将该范围命名为其他名称

所以我的想法是一次找到该作用域,将其分配给一个局部变量,然后,如果我需要访问全局作用域而不是到达window(再一次),则让函数中的所有内容都引用该局部变量。 ,也可以称为其他名称-我不知道)。

我担心的是,这是否会引起一些内存泄漏问题(或者出于其他原因,这可能不是一个好主意)?有什么我应该注意的还是我应该去吗?

function myConstructor() {
    // Is this fundamentally a bad idea?
    var globalScope = findGlobalScope() // Cyclic reference here?

    function findGlobalScope() {
        // Let's say I had some logic here that
        // determinded that I'm running this code
        // in a browser,so Now I kNow `window`
        // is where my global variables are.
        // Keep in mind it may not always be `window`,// but let's say this time it is.
        return window
    }

    this.doWork = function() {
        // In here I reference the `globalScope` variable
        // instead of the `window` variable explicitly.
        // 
        // I'm doing it this way because I don't want
        // my code to break if I run it outside of a browser
        // where I might not have access to an object explicitly
        // named "window"
        console.log(globalScope) // instead of console.log(window)
    }
}

var myObj = new myConstructor()

// Now `myObj` is located at `window.myObj`
// and `myObj` has a reference to `window`
// which... again,has a reference to window.myObj
// Is this something I should be concerned about?

感谢您的帮助。

解决方法

它不是作用域,而是对象。 (但是您可以将其视为一个范围,这是可以理解的;全局范围之一使用它来保存变量。¹)

那绝对很好,不会造成泄漏或其他任何问题。那是一个您知道不会消失的对象(除非您的代码也是如此)。

请注意,JavaScript现在具有globalThis,这正是您所需要的。 :-)这是一个相对较新的功能。


也就是说,as Taplar mentioned,理想情况下,您的代码不应在意全局对象,并且应尽可能避免完全创建全局变量。全局名称空间很拥挤-并且极其在浏览器上很拥挤。

避免使用全局范围的方法:

  1. 使用模块。现代环境支持ES2015的模块。可以通过Webpack或Rollup.js之类的捆绑程序来支持较早的环境。

  2. 如果无法使用模块,请使用包装器功能。如果有必要,因为您的代码必须在运行时拆分为多个文件,请让该函数公开一个名称不明确的全局变量,该全局变量上具有其他功能的属性。

第2个示例(使用ES5语法):

var myStuff = myStuff || {};
(function() {
    myStuff.doSomething = function() {
       // ...
    };
})();

¹这是JavaScript的一个有趣但令人困惑的部分:JavaScript中至少有两个全局作用域,而外部作用域和内部作用域(ES2015 +中的新功能)。

外部变量具有“变量”,它们是全局对象的属性,可以是继承的属性,也可以是自己的属性:如果使用变量名,并且它在当前作用域中不存在,或者在当前作用域与全局范围,但确实作为全局对象上的属性存在,使用了全局对象上的属性-一种旧式的全局变量。当您在全局范围内声明一个函数或使用var声明一个变量时,它会向全局对象添加一个属性。全局对象(在大多数环境中)还从其原型及其原型的原型继承东西。例如,在浏览器上为带有id的元素创建的全局变量是WindowProperties对象的属性,该对象位于全局对象的原型链中。有时它还具有其他“自有”属性,例如name(浏览器上窗口的名称)。

内部全局范围不使用全局对象。这是用letconstclass声明的地方。它们不会成为全局对象的属性。