我最近在javascript中发现with
来执行一个以对象作为当前范围的块。我很好奇是否有一些javascript魔法用函数做同样的事情并在不同的范围内调用它。
示例:
var scope = { foo: 'bar' },
foo = 'baz';
function func(){
return foo;
}
with(scope){
foo; // foo is 'bar'
func(); // foo is still 'baz'
}
在示例中,with
更改了变量foo
的范围,但该函数仍使用定义它的with
之外的范围。有关如何更改或重新定义函数范围的任何建议吗?
答案 0 :(得分:2)
简而言之 - 否
有特殊情况,dynamic binding。它会产生令人困惑的错误,这就是with
语句不能在strict mode中运行的原因。
您案件closes over foo
中的功能。声明函数后,无法更改它引用的foo
。
如果我们必须准确:
语言规范的10.4.3部分描述了“输入功能代码”,这里有趣的是:
让localEnv成为调用NewDeclarativeEnvironment的结果,将F的[[Scope]]内部属性的值作为参数传递。
在我们确定this
之后,在我们将范围设置为刚刚找到的localEnv之前,会发生这种情况。现在这是什么[[Scope]]
?
[[Scope]] - 词法环境 - 定义执行Function对象的环境的词法环境。在标准的内置ECMAScript对象中,只有Function对象实现[[Scope]]。
这意味着函数的范围是事先确定的,而不是基于动态上下文:)
答案 1 :(得分:0)
简而言之 - 是
有特殊情况,dynamic binding。它会产生令人困惑的错误,这就是with
语句不能在strict mode中运行的原因。
然而没有人说我们不能有一点乐趣。我们无法更改函数所具有的闭包变量,但是 - 我们可以利用JavaScript的高度动态性来读取函数的源代码并生成新的绑定。它不是核心语言或通用语言,但对于你认为它确实可行的情况。
以下是您提出的非常基本案例的示例(没有嵌套闭包,没有参数等)。虽然您无法更改闭包,但您可以声明一个运行与另一个相同代码的新函数。让我明确一点 - 这是一个肮脏的黑客;)
var scope = {foo: 'bar'},
foo = 'baz';
var func = function func() {
return foo;
}
// here, `foo` is closed over by the outer foo and it is 'baz'
document.body.innerHTML += " " + func(); // foo is still 'baz'
// foo is bar, since it's a different function here:
document.body.innerHTML += " " + withFunc({foo:"bar"},func);
function withFunc(obj, func) {
//declare a new function
return new Function("obj", // with a parameter obj
"with(obj){\n " + // do `with` on that parameter
"return "+func+"()\n}")(obj); // invoke and return original function
}