如何避免意外地隐式引用全局对象上的属性? [英] How to avoid accidentally implicitly referring to properties on the global object?

查看:45
本文介绍了如何避免意外地隐式引用全局对象上的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在没有默认情况下所有脚本似乎都具有的隐式with(global)上下文的情况下执行代码块?例如,在浏览器中,可以使用任何方法来设置脚本,以使诸如

Is it possible to execute a block of code without the implicit with(global) context that all scripts seem to have by default? For example, in a browser, would there be any way to set up a script so that a line such as

const foo = location;

抛出

未捕获的ReferenceError:未定义位置

Uncaught ReferenceError: location is not defined

当未先声明location时,

而不是访问window.location?缺少这一点,是否有一种方法可以使这种隐式引用导致某种形式的警告?在编写代码时,它可能是错误的来源(见下文),因此有一种防范它的方法可能会很有用.

instead of accessing window.location, when location has not been declared first? Lacking that, is there a way that such an implicit reference could result in a warning of some sort? It can be a source of bugs when writing code (see below), so having a way to guard against it could be useful.

(当然,由于普通的作用域规则,可以使用constlet或在内部块中声明另一个具有相同名称的变量,以确保使用该变量名称引用新变量而不是而不是全局属性,但这不是同一回事.)

(Of course, due to ordinary scoping rules, it's possible to declare another variable with the same name using const or let, or within an inner block, to ensure that using that variable name references the new variable rather than the global property, but that's not the same thing.)

这可能类似于询问是否可以从 actual with语句中停止引用属性:

This may be similar to asking whether it's possible to stop referencing a property from within an actual with statement:

const obj = { prop: 'prop' };
with (obj) {
  // how to make referencing "prop" from somewhere within this block throw a ReferenceError
}

众所周知,不应该首先使用with,但是不幸的是,当我们谈到with(global)时似乎别无选择,它偶尔会节省一些字符,但会浪费一些令人困惑的错误有点频繁: 1 3 4 5 6 .例如:

It's known that with should not be used in the first place, but unfortunately it seems we have no choice when it comes to the with(global), which occasionally saves a few characters at the expense of confusing bugs which pop up somewhat frequently: 1 2 3 4 5 6. For example:

var status = false;
if (status) {
  console.log('status is actually truthy!');
}

(这里的问题:window.status是保留的属性-分配给它时,它会将分配的表达式强制为字符串)

(the issue here: window.status is a reserved property - when assigned to, it coerces the assigned expression to a string)

不鼓励或禁止明确使用with的原因与此类错误相同,但即使在严格模式下,隐式with(global)仍会引起问题,因此找出解决方法将非常有用.

These sorts of bugs are the same reason that explicit use of with is discouraged or prohibited, yet the implicit with(global) continues to cause issues, even in strict mode, so figuring out a way around it would be useful.

推荐答案

在尝试回答此问题之前,您需要考虑一些事项.

There are some things you need to consider before trying to answer this question.

例如,使用 Object 构造函数.它是标准内置对象"

window.status Window界面.

很明显,您不希望status引用window.status,但是您想要Object引用window.Object吗?

Obviously, you don't want status to refer to window.status, but do you want Object to refer to window.Object?

解决无法重新定义它的问题的方法是使用IIFE或模块,无论如何,这应该是您正在做的事情.

The solution to your problem of it not being able to be redefined is to use a IIFE, or a module, which should be what you are doing anyways.

(() => {
  var status = false;
  if (!status) {
    console.log('status is now false.');
  }
})();

为防止意外使用全局变量,我将设置您的linter对其进行警告.使用with (fake_global)之类的解决方案强制执行此操作不仅会在运行时专有地出现错误(可能不会发现错误),而且会更慢.

And to prevent accidentally using global variables, I would just set up your linter to warn against it. Forcing it using a solution like with (fake_global) would not only have errors exclusively at run time, which might be not caught, but also be slower.

特别是对于ESLint,我似乎找不到好的"解决方案.启用浏览器全局变量允许隐式读取.

Specifically with ESLint, I can't seem to find a "good" solution. Enabling browser globals allows implicit reads.

我建议无隐含全局(如您所愿,仍然会污染全局范围,并且可以防止var status没有定义任何问题),也不会启用所有浏览器全局变量,例如,仅windowdocumentconsolesetInterval等,就像您在评论中说的那样.

I would suggest no-implicit-globals (As you shouldn't be polluting the global scope anyways, and it prevents the var status not defining anything problem), and also not enabling all browser globals, only, say, window, document, console, setInterval, etc., like you said in the comments.

查看 ESLint环境,看看您会选择哪种环境喜欢启用.默认情况下,ObjectArray之类的东西在全局范围内,但上面列出的那些和atob的东西不在全局范围内.

Look at the ESLint environments to see which ones you would like to enable. By default, things like Object and Array are in the global scope, but things like those listed above and atob are not.

要查看全局变量的确切列表,它们由定义ESLint globals NPM软件包 .我会从"es6","worker"或"shared-node-browser"的组合中选择.

To see the exact list of globals, they are defined by this file in ESLint and the globals NPM package. I would would pick from (a combination of) "es6", "worker" or "shared-node-browser".

eslintrc文件将具有:

The eslintrc file would have:

{
    "rules": {
        "no-implicit-globals": "error"
    },
    "globals": {
        "window": "readonly",
        "document": "readonly"
    },
    "env": {
        "browser": false,
        "es6": [true/false],
        "worker": [true/false],
        "shared-node-browser": [true/false]
    }
}

这篇关于如何避免意外地隐式引用全局对象上的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆