[英]Is possible to access a closure variable from a eval that is run out of the closure (not using this.variable)? Javascript (Node.js)
test.add("Expect job not to be done.", function(expect){
expect(job.done).toBe(false);
})
这个问题已经更新,我在这里发布了如果有人可能需要它我是如何结束测试的。
原始问题如下......
我知道它甚至可能不可能,但我会清楚地解释为什么以及我希望它如何工作:
我想做一些在缺少某些东西时不会失败的测试,如果存在与否,我不想测试所有内容。
例:
expect('Something', existingClosureVar.notExistingProperty.toString()).toBe('ho ho');
这将抛出这样的错误: TypeError:无法调用未定义的方法'toString'。
解决这个问题很容易,但也很痛苦!
if(existingClosureVar && existingClosureVar.notExistingProperty && existingClosureVar.notExistingProperty.toString){
expect('Something', existingClosureVar.notExistingProperty.toString()).toBe('ho ho');
}
好吧,但如果它不存在我甚至没有注意到失败的测试! 也许一些更详细的解决方法可能会存在,但会使这个代码变得越来越大,当我想要的只是一件简单的事情时,这应该是最简单的事情。
expect('Something', 'existingClosureVar.notExistingProperty.toString()').toBe('ho ho');
不知何故,expect函数应该可以访问闭包的本地变量 ,以使其工作。 它将在try-catch上下文中运行字符串,如果失败,那么测试也会失败。
var callingFn = function(){
var a = 99;
// remember, the eval can't sit here, must be outside
var evalString = 'console.log(a)'; // should print 99
expect(this, evalString); //
}
var expect = function(context, evalString){
var fn = function(){
eval(evalString)
}
fn.call(context);
}
new callingFn(); // creates a this in the callingFn that is not the window object
这需要我使用“这个”。 获取变量的符号。 由于很多函数都是异步的,并且函数的上下文没有被维护(可以维护,但需要更多的工作)(或者我们可以使用闭包变量来保存上下文变量)。
例:
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()
var callingFn = function(){
// setup the context
var context = {};
// give access to the local closure
context.fn = function(evalString){
console.log(eval(evalString))
}
var a = 99;
var evalString = 'a'; // should print 99
expect(context, evalString);
}
var expect = function(context, evalString){
context.fn(evalString);
}
callingFn()
而且我必须在代码前加4行,但是点击这里打开小提琴示例 :
var callingFn = function(expect){
// give access to the local closure
expect.fn = function(evalString){
try {return [undefined, eval(evalString)];
}catch(e){return [e, undefined];}
}
var a = {hey: 1, b: {c: 99}};
console.log(expect('a.b.c', 99)); // true
console.log(expect('a.b.c.d.f', 99)); // return the error
console.log(expect('a.b.c', 44)); // false
console.log(expect('a.hey', 1)); // true
}
var expect = function(evalString, target){
var result = expect.fn(evalString);
var err = result[0];
var output = result[1];
if(err){
return err.stack;
}else{
return output === target;
}
}
callingFn(expect)
var callingFn = function(expect){
// give access to the local closure
var context = {};
expect.context = context;
context.a = {hey: 1, b: {c: 99}};
console.log(expect('a.b.c', 99)); // true
console.log(expect('a.b.c.d.f', 99)); // return the error
console.log(expect('a.b.c', 44)); // false
console.log(expect('a.hey', 1)); // true
}
var expect = function(evalString, target){
var fn = function(evalString){
try {return [undefined, eval('this.' + evalString)];
}catch(e){return [e, undefined];}
}
var result = fn.call(expect.context, evalString);
var err = result[0];
var output = result[1];
if(err){
return err.stack;
}else{
return output === target;
}
}
callingFn(expect)
var callingFn = function(expect){
// give access to the local closure
var a = {hey: 1, b: {c: 99}};
console.log(expect(a, '.b.c', 99)); // true
console.log(expect(a, '.b.c.d.f', 99)); // return the error
console.log(expect(a, '.b.c', 44)); // false
console.log(expect(a, '.hey', 1)); // true
}
var expect = function(object, evalString, target){
var fn = function(evalString){
try {return [undefined, eval('object' + evalString)];
}catch(e){return [e, undefined];}
}
var result = fn(evalString);
var err = result[0];
var output = result[1];
if(err){
return err.stack;
}else{
return output === target;
}
}
callingFn(expect)
//示例适用于Google Chrome,可能无法在其他浏览器中使用。
不, eval
的代码在全局范围内运行。 为什么你需要再次使用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
代码访问闭包中的变量。
使用eval
或Function
构造函数创建的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');
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.