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

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

问题描述

是否可以在没有默认情况下所有脚本似乎都具有的隐式 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;

投掷

未捕获的引用错误:未定义位置

Uncaught ReferenceError: location is not defined

而不是访问 window.location,当 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 2 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.statusWindow 界面的一部分.

window.status is part of the Window interface.

显然,您不希望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.

我建议 no-implicit-globals(因为你不应该无论如何都会污染全局范围,并且它可以防止 var status 没有定义任何问题),并且也不会启用所有浏览器全局变量,例如 window, documentconsolesetInterval 等,就像你在评论中说的.

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.

要查看全局变量的确切列表,它们由此文件定义在 ESLintglobals 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天全站免登陆