是否可以从已用完闭包的eval访问闭包变量(不使用此.variable)?Javascript(Node.js) 最佳方式(国际海事组织):
这个问题已经更新,如果有人需要,我会在这里发布我是如何结束测试的 下面的原始问题 我知道这可能不太可能,但我会清楚地解释我希望它工作的原因和方式: 为什么? 我想做一些测试,当某些东西缺失时不会失败,如果存在或不存在,我不想测试所有东西 例如:是否可以从已用完闭包的eval访问闭包变量(不使用此.variable)?Javascript(Node.js) 最佳方式(国际海事组织):,javascript,closures,eval,Javascript,Closures,Eval,这个问题已经更新,如果有人需要,我会在这里发布我是如何结束测试的 下面的原始问题 我知道这可能不太可能,但我会清楚地解释我希望它工作的原因和方式: 为什么? 我想做一些测试,当某些东西缺失时不会失败,如果存在或不存在,我不想测试所有东西 例如: expect('Something', existingClosureVar.notExistingProperty.toString()).toBe('ho ho'); var callingFn = function(){ var cont
expect('Something', existingClosureVar.notExistingProperty.toString()).toBe('ho ho');
var callingFn = function(){
var context = {b: 1};
var evalString = 'b'; // prints 1
expect(context, evalString)
}
var expect = function(context, evalString){
var fn = function(){
console.log(eval('this.' + evalString))
}
fn.call(context);
}
callingFn()
这将引发如下错误:TypeError:无法调用未定义的方法“toString”。
解决这个问题很容易,但也很痛苦
if(existingClosureVar && existingClosureVar.notExistingProperty && existingClosureVar.notExistingProperty.toString){
expect('Something', existingClosureVar.notExistingProperty.toString()).toBe('ho ho');
}
好吧,但如果它不存在,我甚至没有注意到考试不及格!可能存在一些更详细的解决方法,但会使代码越来越大,而我只需要一件简单的事情,这应该是最短的事情
我们应该如何取而代之?
expect函数应该能够访问闭包的局部变量,以实现此功能。它将在try-catch上下文中运行字符串,如果失败,测试也将失败
正是我想要的:
如果我提供一个上下文,它是有效的,但是。。。
这需要我使用“this.”符号来获取变量。因为很多函数是异步的,并且函数的上下文没有维护(可以维护,但是需要做更多的工作)(或者我们可以使用闭包变量来保存上下文变量)
例如:
expect('Something', existingClosureVar.notExistingProperty.toString()).toBe('ho ho');
var callingFn = function(){
var context = {b: 1};
var evalString = 'b'; // prints 1
expect(context, evalString)
}
var expect = function(context, evalString){
var fn = function(){
console.log(eval('this.' + evalString))
}
fn.call(context);
}
callingFn()
我发现了一个丑陋的解决方案:
可行的解决方案,但仍然过于冗长:
我还必须在代码前放4行,但这里是:
共享上下文:
本地变量+字符串:
//例如Google Chrome,它可能无法在其他浏览器中运行。不,
eval
'd代码在全局范围内运行。为什么需要再次使用eval
使用匿名函数而不是将代码放在字符串中,所有与作用域相关的问题都将消失
var callingFn = function() {
var a = 99;
// remember, the eval can't sit here, must be outside
expect(this, function() {
console.log(a);
});
}
var expect = function(context, callable) {
try {
callable.call(context);
}
catch(ex) {
// handle exception
}
}
演示:总之,不。您无法从
eval
code访问闭包中的变量
使用eval
或Function
构造函数创建的函数始终在全局范围(或在严格模式下,未定义范围)中运行。这是无法避免的
此外,您不能从函数外部(或函数内部)访问函数的作用域。这是因为JavaScript具有静态作用域;范围在声明时是固定的。函数不能更改其作用域链
如果您只是希望在属性未定义的情况下测试失败,最简单的方法可能是:
if (obj && obj.prop) expect('Some Test', obj.prop) ...
else fail('Some Test');
或者使用其调用包装在try
中的回调
expect('Some Test', function() {
return obj.prop;
}).toBe('some value');
expect
可以使用回调的返回值,或者如果您知道始终会定义有问题的标识符,则允许您传递一个简单的值
function expect(name, o) {
var expectedValue;
if (typeof o == 'function') {
try { expectedValue = o(); }
catch(ex) { /* fail here */ }
} else expectedValue = o;
...
}
因此,您可以通过任何一种方式调用expect
:
function callingFn() {
var localVar = 1, someObj = {};
expect('Test var', localVar).toBe(1);
expect('Test obj', function() { return someObj.missingProp.toString(); }).toBe('value');
}
这也是一个很好的想法,但是如果可能的话,我真的希望不必为每个expect定义一个新函数,因为这就是我提出这个问题的原因。我的目标是尽可能使用更少的代码和更干净的代码,即使我必须使用eval。。但是谢谢你的回答。这就是如何做到的。不能使用eval编写干净的代码。尤其是当您需要访问正在定义代码字符串的本地范围时。但是使用“if(obj&&obj.prop)”或“try{function}catch(){}”仍然需要详细说明IMO。这就是为什么我选择要求使用最不详细的方法来完成此操作。感谢您的回复;)这个“expect('Test obj',function(){return someObj.missingProp.toString();}).toBe('value');”和“expect('Test obj','someObj.missingProp.toString()).toBe('value');”之间的区别并没有那么大,我知道,但我不想在每个expect调用中到处都看到函数。坦白地说,我认为你不会比我在最后一个例子中看到的更好。由于作用域是静态的,并且eval总是在全局作用域中运行,如果没有在目标变量的作用域中定义函数,就不可能实现目标。此外,这是JavaScript;没有必要担心匿名回调函数。我不担心,我只是想知道是否有可能进行更干净的测试。为每个expect变量使用函数有点太多了sEh-它是额外的18个字符。依我看,这比你的问题中的任何一个选择都要少。
var callingFn = function() {
var a = 99;
// remember, the eval can't sit here, must be outside
expect(this, function() {
console.log(a);
});
}
var expect = function(context, callable) {
try {
callable.call(context);
}
catch(ex) {
// handle exception
}
}
if (obj && obj.prop) expect('Some Test', obj.prop) ...
else fail('Some Test');
expect('Some Test', function() {
return obj.prop;
}).toBe('some value');
function expect(name, o) {
var expectedValue;
if (typeof o == 'function') {
try { expectedValue = o(); }
catch(ex) { /* fail here */ }
} else expectedValue = o;
...
}
function callingFn() {
var localVar = 1, someObj = {};
expect('Test var', localVar).toBe(1);
expect('Test obj', function() { return someObj.missingProp.toString(); }).toBe('value');
}