Javascript 为什么嵌套的 describe() 块不能看到外部块中定义的变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28546182/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't nested describe() blocks see vars defined in outer blocks?
提问by Ken Bellows
I've run into this issue in real code, but I put together a trivial example to prove the point.
我在实际代码中遇到过这个问题,但我整理了一个简单的例子来证明这一点。
The below code works fine. I've set up a variable in my root describe()block that is accessible within my sub-describe()s' it()blocks.
下面的代码工作正常。我已经成立了以我的根可变describe()块是我的子内访问describe()s'的it()块。
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
var trees = orchard.trees;
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
var trees = orchard.trees;
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
However, if I try to DRY up my code a little by doing the following, it breaks:
但是,如果我尝试通过执行以下操作来稍微干燥我的代码,它会中断:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
var trees = orchard.trees; // TypeError: Cannot read property 'trees' of undefined
it ('should have apples and oranges', function() {
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
Within the nested describe()scope, the orchardobject is undefined, even though it's defined within the it()blocks within it.
在嵌套describe()范围内,orchard对象是未定义的,即使它是在其中的it()块中定义的。
Is this intentional on the part of Jasmine's developers, possibly to avoid issues with resetting the object in beforeEach()and possible breaking some references? How do they make it happen? I could see how this might be useful, I'm just very curious as to how it works. (My guess is some apply()or call()magic, but I'm not sure how...)
这是否是 Jasmine 的开发人员有意为之,可能是为了避免重置对象beforeEach()和可能破坏某些引用的问题?他们是如何做到的?我可以看到这可能会有什么用处,我只是很好奇它是如何工作的。(我的猜测是一些apply()或call()魔法,但我不确定如何......)
--
——
As a side-note, I can still DRY up my code by simply using another beforeEach()block:
作为旁注,我仍然可以通过简单地使用另一个beforeEach()块来干掉我的代码:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
var trees;
beforeEach(function() {
trees = orchard.trees;
});
it ('should have apples and oranges', function() {
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
回答by Andrew Eisenberg
This is exactly as expected. The problem is that your var treesvariable is trying to access orchardbefore it has been initialized. The body of a describe block is executed before the beforeEachblocks. To solve this problem, the third code snippet is the only way to go.
这完全符合预期。问题是您的var trees变量orchard在初始化之前试图访问。描述块的主体在块之前执行beforeEach。为了解决这个问题,第三个代码片段是唯一的出路。
Jasmine will first execute the describe blocks, and then execute the beforeEach blocks before running each test.
Jasmine 将首先执行 describe 块,然后在运行每个测试之前执行 beforeEach 块。
回答by aeje
Well you could still initialize variables outside the beforeEach block. I generally do it for constants and still remain DRY without introducing beforeEach blocks.
好吧,您仍然可以在 beforeEach 块之外初始化变量。我通常为常量这样做,并且仍然保持 DRY 而不引入 beforeEach 块。
describe('simple object', function () {
const orchard = {
trees: {
apple: 10,
orange: 20
},
bushes: {
boysenberry: 40,
blueberry: 35
}
};
describe('trees', function () {
const trees = orchard.trees;
it('should have apples and oranges', function () {
expect(trees.apple).toBeDefined();
expect(trees.orange).toBeDefined();
expect(trees.apple).toEqual(10);
expect(trees.orange).toEqual(20);
});
it('should NOT have pears or cherries', function () {
var trees = orchard.trees;
expect(trees.pear).toBeUndefined();
expect(trees.cherry).toBeUndefined();
});
});
});
回答by now he who must not be named.
Lets take the third code snippet. Further, it can be refactored as below:
让我们看第三个代码片段。此外,它可以重构如下:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
expect (orchard.trees.apple).toBeDefined();
expect (orchard.trees.orange).toBeDefined();
expect (orchard.trees.apple).toEqual(10);
expect (orchard.trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (orchard.trees.pear).toBeUndefined();
expect (orchard.trees.cherry).toBeUndefined();
});
});
});
For the new comers to Jasmine, this is how you intrepret the above code :\
对于Jasmine的新手,您可以这样解释上述代码:\
describedefines atest suite. Thetest suitename here is a user defined simple string, say "simple object".- A
test suitecan itself contain othertest suites, meaningdescribecan contain nested suites. - Just like other programming languages,
orchidis global to all the functions & suites defined withinsimple objecttest suite. Itblock is called aspecificationor aSPEC.Itblocks contain individual tests.- Just when
Jasmineexecutes the test cases, it will first visit theitblocks meaning it will traverse all theitblock declarations. - When
Jasmineactuallyexecutes test cases, it will check forbeforeEachfunction and henceorchardgetstreesvalue assigned to it. And hence you need not write a beforeEachfunction, inside a
sub suite. You can simply ignorebeforeEach (function() { trees = orchard.trees; });
Now compare the latest snippet below with the third snippet above.
describe定义一个test suite.test suite这里的名称是用户定义的简单字符串,比如“简单对象”。- A
test suite本身可以包含 othertest suites,这意味着describe可以包含嵌套套件。 - 就像其他编程语言一样,测试套件中
orchid定义的所有功能和套件都是全局的simple object。 It块被称为 aspecification或 aSPEC。It块包含单独的测试。- 就在
Jasmine执行测试用例时,它将首先访问it块,这意味着它将遍历所有it块声明。 - 当
Jasmine实际执行测试用例时,它会检查beforeEach功能并因此orchard获得trees分配给它的值。 因此,您无需在 a 中编写 beforeEach函数
sub suite。你可以简单地忽略beforeEach (function() { tree = orchard.trees; });
现在将下面的最新片段与上面的第三个片段进行比较。

