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]
}
}