我是否正在创建一个全局变量

Am I creating a global variable?

本文关键字:一个 全局变量 是否 创建      更新时间:2023-09-26

我正在创建一个使用 Jasmine 测试 Angular 滤镜的函数。这些规范由Karma运行。这个想法是传递一个模块和过滤器名称,以及要对其执行的测试数组。该数组的每个元素都有一个描述、一个输入值和一个预期结果。但它也可以包含一个 testSteps 函数,用于测试,这些测试不像传递输入值并期望精确值那么简单。我正在制作的函数旨在创建相应的 Jasmine 描述,并为测试阻止,它位于定义如下的全局变量中:

var $uite = {
    testFilter : function(filterName, moduleName, tests) {
        this.filterObject = null;
        this.isDefined = function(vble) {
            return typeof (vble) != 'undefined';
        }
        describe('FILTER: ' + filterName, function() {
            beforeEach(module(moduleName));
            beforeEach(inject(function($filter) {
                filterObject = $filter(filterName);
            }));
            for (var i = 0; i < tests.length; i++) {
                var test = tests[i];
                it(test.it, function() {
                    if (typeof (test.forInputValue) != 'undefined') {
                        var result = filterObject(test.forInputValue);
                        expect(result).toEqual(test.resultShouldBe);
                    } else if (typeof (test.testSteps) != 'undefined') {
                        test.testSteps();
                    }
                });
            }
        });
    }
}

我的测试代码是:

$uite.testFilter('nameFilter', 'app', [ {
    it : 'gets male gender from a name ending in O',
    forInputValue : 'Pedro',
    resultShouldBe : 'el tal Pedro'
}, {
    it : 'gets female gender from a name ending in A',
    forInputValue : 'Carolina',
    resultShouldBe : 'la tal Carolina'
}, {
    it : 'transforms Lina into la tal Lina',
    testSteps : function() {
        var result = filterObject('Lina');
        expect(result).toEqual('la tal Lina');
    }
} ]);

它工作得很好,但只是出于好奇,因为我避免创建不必要的全局变量,所以我在它们之后编写了以下测试:

describe('some test',function(){
    it('works',function(){
        expect(typeof(filterObject)).toEqual('undefined');
    });
});

失败是因为过滤器对象的类型是函数。如果我的 filterObject 是在 $uite 对象内部定义的,并且没有(是吗?(隐式声明,那么为什么可以从另一个描述/it 块集访问它?

您的问题:我是否在创建全局变量?

博士

是的

完整答案

它是全球性的。您在这里将其推向全球:

filterObject = $filter(filterName);

如果您没有在此之前放置var,并且您没有使用严格模式(例如 use strict; (,那么它将是一个全球性的。

如果你想让它引用this,你需要在任何地方使用this

beforeEach(inject.call(this, function($filter) {
    this.filterObject = $filter(filterName);
}.bind(this)));

或类似的东西。或者,您可以声明var _this = this

beforeEach(inject(function($filter) {
    _this.filterObject = $filter(filterName);
}));

在整个代码中的其他任何地方,都需要将其称为 this.filterObject

仅供参考,关于严格模式的说明(关于 MDN 的文章((我总是建议使用它,因为它会捕获意外的全局变量(来自"将错误转换为错误"部分:

首先,严格模式使得不可能意外创建全局变量。

其他参考资料:

  1. Function.prototype.bind on MDN
  2. Function.prototype.call on MDN

附言:看起来你来自Java背景。使用对象时,定义this.<whatever>然后尝试将其简单地称为<whatever>在 JavaScript 中不起作用,就像你期望它在 Java 中工作一样。

编辑

要在第三次测试中访问filterObject,请执行以下操作:

// ... in $suite
} else if (typeof (test.testSteps) != 'undefined') {
    // make this.filterObject available as a parameter
    test.testSteps(this.filterObject);
}
// then in your test definition...
}, {
    it : 'transforms Lina into la tal Lina',
    testSteps : function(filterObject) {  // this line is important
        var result = filterObject('Lina');
        expect(result).toEqual('la tal Lina');
    }
} ]);