Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/432.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何避免意外地隐式引用全局对象上的属性?_Javascript_Scope_With Statement - Fatal编程技术网

Javascript 如何避免意外地隐式引用全局对象上的属性?

Javascript 如何避免意外地隐式引用全局对象上的属性?,javascript,scope,with-statement,Javascript,Scope,With Statement,是否可以在没有默认情况下所有脚本都具有的隐式和(全局)上下文的情况下执行代码块?例如,在浏览器中,是否有任何方法设置脚本,以便 const foo = location; 投掷 未捕获引用错误:未定义位置 不是访问窗口.位置,而是在未首先声明位置时?如果没有这一点,有没有一种方式可以让这种隐含的引用导致某种警告?在编写代码时,它可能是bug的来源(见下文),因此有一种方法来防范它可能很有用 (当然,由于普通的作用域规则,可以使用const或let或在内部块内声明另一个同名变量,以确保使用该变量

是否可以在没有默认情况下所有脚本都具有的隐式
和(全局)
上下文的情况下执行代码块?例如,在浏览器中,是否有任何方法设置脚本,以便

const foo = location;
投掷

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

不是访问
窗口.位置
,而是在未首先声明
位置
时?如果没有这一点,有没有一种方式可以让这种隐含的引用导致某种警告?在编写代码时,它可能是bug的来源(见下文),因此有一种方法来防范它可能很有用

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

这可能类似于询问是否可以使用语句从实际的
中停止引用属性:

const obj = { prop: 'prop' };
with (obj) {
  // how to make referencing "prop" from somewhere within this block throw a ReferenceError
}
众所周知,首先不应使用
with
,但不幸的是,对于
with(全局)
,我们似乎别无选择,这有时会节省一些字符,但会导致出现一些比较频繁的错误:。例如:

var状态=false;
如果(状态){
log('状态实际上是truthy!');

}
如果您不是在严格模式下,一种可能是迭代全局(或
with
ed)对象的属性名称,并从这些属性创建另一个对象,其setter和getter都抛出
ReferenceErrors
,然后将代码嵌套在另一个
with
对象上。请参阅下面代码中的注释

这不是一个好的解决方案,但这是我唯一能想到的:

const makeObjWhosePropsThrow=inputObj=>Object.getOwnPropertyNames(inputObj)
.reduce((a,propName)=>{
const doThrow=()=>{throw new ReferenceError(未定义propName+');};
defineProperty(a,propName,{get:doThrow,set:doThrow});
返回a;
}, {});
//(使用setTimeout以便控制台显示此错误和下一个错误)
设置超时(()=>{
const windowWhichThrows=makeObjWhosePropsThrow(窗口);
带(窗向上){
/*利用生命
*因此,具有相同名称的变量在内部声明为“var”
*创建一个局部作用域变量
*而不是尝试引用属性,这样会
*/
(() => { 
//声明任何变量名都不会引发:
var alert=true;//window.alert
const open=true;//window.open
//在不首先声明属性名称的情况下引用属性名称将引发:
const foo=位置;
})();
}
});
const obj={prop1:'prop1'};
带(obj){
const inner=makeObjWhosePropsThrow(obj);
带(内部){
//在不首先声明属性名称的情况下引用属性名称将引发:
console.log(prop1);
}
}
。作为控制台包装器{
最大高度:100%!重要;
}
也许稍微干净一点(YMMV)就是设置getter陷阱(就像你做的那样),但是在一个worker中,这样你就不会污染你的主要全局范围。不过,我不需要将
一起使用,所以这可能是一种改进

工作者“线程”

主“线程”


另一个值得探索的选项是。

只需使用
“严格使用”
。更多关于


<> P>在回答这个问题之前,你需要考虑一些事情。

例如,以构造函数为例。这是一个好主意

这是我们的一部分

显然,您不希望
status
引用
window.status
,但是否希望
Object
引用
window.Object


解决it无法重新定义的问题的方法是使用IIFE或模块,不管怎样,这应该是您正在做的事情

(() => {
  var status = false;
  if (!status) {
    console.log('status is now false.');
  }
})();
为了防止意外使用全局变量,我只需要设置你的linter来警告它。使用类似于
和(fake_global)
的解决方案来强制它,不仅在运行时会出现唯一的错误,这可能不会被捕获,而且会更慢


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

我建议(因为你无论如何都不应该污染全局范围,它可以防止
var状态
不定义任何问题),也不要像你在评论中所说的那样,只启用所有浏览器全局,比如
窗口
文档
控制台
设置间隔
,等等

查看以查看要启用哪些。默认情况下,像
Object
Array
这样的东西在全局范围内,但是上面列出的那些东西和
atob
不在全局范围内

要查看全局变量的确切列表,它们由和定义。我会从“es6”、“worker”或“shared node browser”的组合中进行选择

eslintrc文件将具有:

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

实现起来比@CertainPerformance的答案要简单一些,您可以使用来捕获对除
窗口
之外的所有内容的隐式访问。唯一需要注意的是,您不能在严格模式下运行此操作:

const strictWindow=Object.create(
新代理(窗口{
获取(目标、属性){
if(typeof属性!=='string')返回未定义
log(`implicit access to${property}`)
抛出新引用错误(`${property}未定义`)
}
}),
Object.getOwnPropertyDescriptors({window})
)
带(窗口){
试一试{
const foo=位置
}捕获(错误){
window.console.log(error.toString())
}
//不是吗
(() => {
  var status = false;
  if (!status) {
    console.log('status is now false.');
  }
})();
{
    "rules": {
        "no-implicit-globals": "error"
    },
    "globals": {
        "window": "readonly",
        "document": "readonly"
    },
    "env": {
        "browser": false,
        "es6": [true/false],
        "worker": [true/false],
        "shared-node-browser": [true/false]
    }
}