function a(){ return x++; }
function b(){ var x=0; return a(); /*call a using b's scope*/ };
console.log(b(),b(),b());
所需输出:1、2、3
问题:有没有办法调用a
inside b
,强制它使用b
's 范围?
function a(){ return x++; }
function b(){ var x=0; return a(); /*call a using b's scope*/ };
console.log(b(),b(),b());
所需输出:1、2、3
问题:有没有办法调用a
inside b
,强制它使用b
's 范围?
不完全是,但你可以在它周围包裹一个闭包:
(function() {
var x = 0;
window.a = function() {return x++;};
window.b = function() {return a();};
console.log(b(),b(),b());
})();
您的问题可以分解为两部分:
第一部分可以使用eval
. 阅读以下 StackOverflow 问题以获取更多详细信息:是否可以在不使用 eval 的情况下在 JavaScript 中实现动态范围?
第二部分要求您将变量的中间值存储在x
某处,并在每次函数调用后恢复它。在这种情况下存储它的最佳位置是函数b
本身。
这就是您的代码的样子:
function a() {
return ++x; // I believe you want prefix increment, not postfix
}
function b() {
var x = b.x;
eval(String(a)); // dynamic scoping
b.x = a();
return x;
}
b.x = 0;
console.log(b(), b(), b());
你可以在这里看到演示:http: //jsfiddle.net/ucGxD/1/
不,范围仅来自函数的定义方式。
您必须使用参数(和闭包)传递数据才能将 b 范围内的某些内容放入 a 中。
您的确切示例不起作用(因为x
每次调用时都会重新初始化b
),但请考虑:
x = 100;
function a() { return x++; }
function b() {
var x = 0;
console.log(a(), a(), a()); // 100 101 102
eval(a.toString())
console.log(a(), a(), a()); // 0 1 2
}
不用说,不要在工作中尝试。
不,没有。这绝对是一个功能。
更新
由于这里的一些答案和评论建议使用function.toString
和eval
模拟动态范围,让我总结一下为什么我认为这不是一个合适的解决方案(无论如何都是一个坏主意):
语言标准没有规定调用toString
函数的结果,也不打算用于这种用途。它恰好适用于大多数(用户定义的)功能的当前浏览器,但不能保证这一点,我强烈建议不要编写依赖它的生产代码。
函数远不止字符串化可以给你的一段文本。特别是,函数是具有标识和携带状态的对象,字符串化不能保留这两者。更确切地说:
函数可以具有函数体可以访问的属性(特别是prototype
属性)。它们将在字符串化过程中丢失。
函数有一个闭包环境,封装了它们使用的周围范围的变量。同样,这将丢失,导致悬空或错误绑定变量引用(即使这可能是其中一些练习的目的)。
函数还有其他可能相关的属性,比如它们的身份、修改__proto__
的 或配置状态,比如不可扩展。这些都没有被保留。
并非所有函数都是简单的 JavaScript 源函数。它们可能是原生的,或者从 ES6 开始,它们可能是函数代理。在这两种情况下,字符串化都不会有用。
具有未绑定变量引用的函数在严格模式下是不合法的(因此在 ES6 中的许多地方都是非法的)。
因此,虽然字符串化可能在一些简单的情况下起作用,但这是偶然的,而不是设计使然。这是一个脆弱的黑客。避开它。
是的。上下文可以通过call或apply转移。您可以通过调用bind来将上下文设置为范围。看这个例子:
function a() {
return ++this.x;
}
function b() {
this.x = this.x || 0;
return a.call(this); // a works with x in b's context
}
b = b.bind(b); // now the b's context is the b's scope :-)
console.log(b(),b(),b()); // 1 2 3
console.log(x); // error: x is not defined - global scope is clear
正如 Quentin 所指出的,请参见此处的上下文和范围之间的区别。