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%!重要;

}
如果您不是在严格模式下,一种可能是迭代全局(或
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中,这样你就不会污染你的主要全局范围。不过,我不需要将
一起使用,所以这可能是一种改进

工作者“线程”

主“线程”


另一个可能值得探索的选择是。

也许稍微清洁一点(YMMV)是设置吸气剂陷阱(就像你做的那样),但在一个工人身上,这样你就不会污染你的主要全球范围。不过,我不需要将
一起使用,所以这可能是一种改进

工作者“线程”

主“线程”


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

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

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


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

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

这是我们的一部分

显然,您不需要//worker; foo.js addEventListener('message', function ({ data }) { try { eval(` for (k in self) { Object.defineProperty(self, k, { get: function () { throw new ReferenceError(':('); } }); } // code to execute ${data} `); postMessage('no error thrown '); } catch (e) { postMessage(`error thrown: ${e.message}`); } });
var w = new Worker('./foo.js');
w.addEventListener('message', ({data}) => console.log(`response: ${data}`));
w.postMessage('const foo = location');
(() => {
  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]
    }
}