改变功能的范围

时间:2013-09-25 23:04:58

标签: javascript

我最近在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之外的范围。有关如何更改或重新定义函数范围的任何建议吗?

2 个答案:

答案 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 
}

http://jsfiddle.net/42YX4/