2

我最近with在 javascript 中发现以对象作为当前范围来执行块。我很好奇是否有一些 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。关于如何更改或重新绑定函数范围的任何建议?

4

2 回答 2

2

简而言之 -

with 很特别,它做动态绑定。它会产生令人困惑的错误,这就是with语句不在严格模式下运行的原因。

您的情况下的功能关闭了 foo。一旦函数被声明,就无法更改foo它引用的内容。


如果我们必须精确:

语言规范的第10.4.3节描述了“输入功能代码”,这里有趣的是:

让 localEnv 成为调用 NewDeclarativeEnvironment 的结果,并将 F 的 [[Scope]] 内部属性的值作为参数传递。

这发生在我们弄清楚this之后并且在我们将范围设置为我们刚刚找到的 localEnv 之前。现在这是什么[[Scope]]

[[Scope]] - Lexical Environment - 定义执行 Function 对象的环境的词法环境。在标准的内置 ECMAScript 对象中,只有 Function 对象实现 [[Scope]]。

这意味着函数的范围是事先决定的,而不是基于动态上下文:)

于 2013-09-25T23:10:18.773 回答
0

简而言之 -是的

with 很特别,它做动态绑定。它会产生令人困惑的错误,这就是with语句不在严格模式下运行的原因。

然而没有人说我们不能有一点乐趣。然而,我们不能改变函数的闭包变量——我们可以利用 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 
}

http://jsfiddle.net/42YX4/

于 2013-09-25T23:54:09.057 回答