繁体   English   中英

在Javascript中访问内部函数变量

[英]Access inner function variables in Javascript

例如,在许多框架中,内部函数变量用作私有变量

Raphael = (function(){
    var _private = function(a,b) {return a+b;};
    var _public = function(a) {return _private(a,a);}
    var object = {mult2:_public};
    return object;
})();

在这里,我们无法从全局命名空间访问名为private的变量,因为它是第一行中匿名函数的内部变量。

有时这个函数包含一个大的Javascript框架,因此它不会污染全局命名空间。

我需要对Raphael内部使用的一些对象进行单元测试(在上面的例子中,我希望对private对象运行单元测试)。 我该如何测试它们?

编辑:我收到了关于应该测试公共接口的单元测试的评论。

我来指一个用例。 我正在写一个名为Raphael的图书馆。 该库应该只向全局命名空间添加一个名称,仅此而已。 这是Javascript的特殊要求,因为Javascript没有名称空间。

让我们说Raphael使用链表。 如果Javascript有包的概念,我会这样做

require 'linked_list'
Raphael = (function(){/* use linked list */})();

但是,Javascript不允许我以任何不会使用链表对象污染全局范围的方式执行此操作! 因此,我必须将linked_list内联到Raphael的本地范围:

Raphael = (function(){
    /* implement linked list */
    var linked_list = function(){/*implementation*/};
})();

现在我想测试linked_list实现。

你仍然忽略了这一点。

单元测试的要点是验证对象的公共接口是否符合预期。 单元测试显示代码的工作原理。

唯一应该测试的是对象的公共接口。 这样,当开发人员想要更改对象的实现方式时,您只会担心被测对象是否仍然能够实现预期的对象。

如果你觉得那个闭包里面的对象需要测试,那么测试一下,但是在外部做,然后把它传递给闭包。

var Raphael= function(listIterator) {
  listIterator.method();
}(new ListIterator());

虚假黑客,如下所示,是完全不合适的(在单元测试或任何地方)。

测试函数应该很简单,只测试一件事,并有一个断言。 这通常发生在三到十行测试代码中。

当你到达测试函数复杂的程度时,因为他们将遵循你所询问的方法,然后(1)意识到你的设计可能不是你想要的那样并改变它以便它是,或(2)改变您对测试的期望。

关于您发布的代码,您忘记了var ,错过了分号,并使用了两个保留字作为标识符: privatepublic

不使用var是可能触发与非标准GlobalScopePolluter类型对象的各种实现相关的错误和问题(“对象不支持IE中的此属性或方法”)。 使用FutureReservedWord的结果是SyntaxError FutureReservedWord as identifier, and indeed many do, however it is best to not rely on such extensions and if you got an error, it would be completely your fault. 实现可以提供语法扩展以 FutureReservedWord作为标识符,实际上很多都可以,但是最好不要依赖这样的扩展,如果你遇到错误,那将完全是你的错。

您提到过向用户提供代码。 我建议你不要那样做,直到你获得更多的经验和理解你正在做的事情。

// DO NOT USE THIS CODE.
var Raphael = (function(){
    var _private = function(a,b) {return a+b;};
    var _public = function(a) {return _private(a,a);};
    var object = {mult2:_public};
    return object;
})();

var leakedFunction;

// Spurious hack:
//   Give valueOf a side effect of leaking function.
//   valueOf is called by the _private function as a
//   side effect of primitive conversion, where 
//   ToPrimitive(input argument, hint Number) results 
//   in calling valueOf.

function valueOfSnoop(){ 
    leakedFunction = leakedFunction || valueOfSnoop.caller || function(){};
    return 2;
}

var a = {
  valueOf : valueOfSnoop
};

Raphael.mult2(a, 3);
var privateMathod = leakedFunction;
alert(leakedFunction(1, 2));

该示例代码仅用于证明这样的事情是可能的。 鉴于这种选择,它是前面提到的替代品的不良替代品; 要么改变你的设计,要么改变你的测试。

试试这个:

var adder = function(a,b) {
    return a + b;
}

Raphael = function(fn){
    var _private = function(a,b) {
        fn(a,b);
    }

    var _public = function(a) {
        return _private(a,a);
    }

    var object = {doubleIt: _public};

    return object;
}(adder);

只需一点功能注射

我提出的最佳解决方案:

在源Javascript文件中使用

Raphael = (function(){
// start linked_list
    var linked_list = function() {/*...*/};
// end linked_list
    var object = {mult2:_public};
    return object;
})();

现在,使用脚本在// start ([a-zA-Z_]*)// end ([a-zA-Z_]*)之间提取对象,并对提取的代码进行单元测试。

显然,不可能从外部作用域访问函数内部范围中的变量。 正如在评论中与杰森联系的SO问题所写的那样。

var Raphael;
var test = true; //or false;

Raphael = (function(){
    var private = function(a,b) {return a+b;};
    var public = function(a) {return private(a,a);}
    var object = {mult2:public};

    if (test) Raphael.private = private;

    return object;
})();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM