JavaScript闭包无法访问外部变量

时间:2014-02-14 20:17:13

标签: javascript nvd3.js

我有这样的代码并且不知道为什么在传递给nv.addGraph()的匿名函数中我无法访问外部函数中的变量,如 a zcls this.model

function (out) {
// Here you call the "this" means the widget instance. (@see Mylable.js)
var zcls = this.getZclass(),
uuid = this.uuid;

// The this.domAttrs_() means it will prepare some dom attributes,
// like the pseudo code below
/*
 * class="${zcls} ${this.getSclass()}" id="${uuid}"
 */
var a = this.domAttrs_();
out.push('<span ', this.domAttrs_(), '>fds</span><div id="chart"><svg></svg></div>');



nv.addGraph(function() {
    var chart = nv.models.multiBarChart()
    .transitionDuration(350)
    .reduceXTicks(true)   // If 'false', every single x-axis tick label
    // will be rendered.
    .rotateLabels(0)      // Angle to rotate x-axis labels.
    .showControls(true)   // Allow user to switch between 'Grouped' and
    // 'Stacked' mode.
    .groupSpacing(0.1)    // Distance between each group of bars.
    ;

    chart.xAxis.tickFormat(d3.format(',f'));

    chart.yAxis.tickFormat(d3.format(',.1f'));

    var data = [{
        key: 'Some key',
        color: '#ff44ee',
        values: [{
            x: 1,
            y: 3
        }, {
            x: 3,
            y: 4
        }]
    }]

    d3.select('#chart svg').datum(data).call(chart);
//      d3.select('#chart svg').datum(this.model.data).call(chart);

    var someData = this.model.data;

    nv.utils.windowResize(chart.update);
    return chart;
});

这个函数以某种方式在ZKoss Widget中使用,所以在这个函数中可以访问它的属性,比如this.model,但是在内部匿名函数中是不可能的。我不知道它有什么问题,我刚开始用JS编码。

3 个答案:

答案 0 :(得分:1)

您在关闭时无法访问azcls,但您应该没有问题。

至于this,它总是一个函数本地引用,由函数的调用者设置。如果您想要访问父函数所查看的this,您需要将其复制到本地变量,例如,

var that = this;
在父级中

然后在闭包中引用that而不是this,或者,您可以在传递此函数的函数上调用bind(),例如。

nv.addGraph(function () {
   ...
}.bind(this));

这将导致函数中的this与父{〗this的值相同。

答案 1 :(得分:1)

JavaScript中的this关键字与其他OO语言(例如Java)的工作方式不同。它的值是在运行时确定的,它完全取决于我们调用函数的方式。

可以通过四种不同的方式调用函数:

  1. 构造函数调用:使用new关键字;这是指新创建的实例

    function Car = function(){// ...} var car = new Car();

  2. 函数调用:调用某个范围中定义的函数时,例如全局范围。在这种情况下,这指的是全局对象

    function someFunc(){} someFunc();

  3. 方法调用:调用定义为对象成员的函数时。例如

    var obj = {func:function(){}} obj.func();

  4. 在这种情况下,这指向对象本身。

    4调用/应用:最后,可以借助在Function构造函数原型上定义的两个方法调用函数。在这种情况下,我们可以自己设定价值;     var obj = {func:function(){}}     function someFunc(){}

    someFunc.call(obj);
    

    在您的情况下,为了访问this.model,您需要明确定义this关键字指向的位置。

    你必须选择:

    1. 定义一个局部变量,例如var that = this;
    2. 使用ES5 bind方法

      nv.addGraph(function(){    ... } .bind(本));

答案 2 :(得分:0)

内部匿名函数的范围与包含函数的范围相同。

您可以考虑传入zcls,或者在传递给nv.addGraph

的函数中定义它

MDN解释得非常好: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope

您可以定义函数参数,然后按名称传递它。例如:

var fcnArg = function() { ... }

nv.addGraph(fcnArg);

这里有另一个很好的讨论: Passing a function as an argument in a javascript function