JavaScript 中的范围(我认为?!)挑战 [英] Scope (I think?!) challenge in JavaScript

查看:32
本文介绍了JavaScript 中的范围(我认为?!)挑战的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 CreateJS,我输出了一个带有各种对象实例的画布,以各种方式制作动画.几乎所有工作都正常,除了一个问题,我认为是一个范围问题,但我不知道如何解决.我有一个由_pulsars"引用的实例,包含对象pulsar"的 11 个实例,代码运行如下:

Using CreateJS, I have output a canvas with instances of various objects, animating in various ways. Almost all is working ok, except for one issue, which I think is a scope issue, but I'm not sure how to fix. I have an instance referenced by '_pulsars', containing 11 instances of an object 'pulsar', and code runs like this:

function attachPulseFuncs() {

    var defaultFreq = 0.05; // controls the likelihood of a 'pulse' happening

    for (var i = 0; i < _pulsars.children.length; i++) {

        var myParent = _pulsars.children[i];

        myParent.isPulsing = false;

        _myParent.pulse = function() {
            if (myParent.isPulsing == false) {
                myParent.isPulsing = true;
                myParent.__frame = 1
                var tween = createjs.Tween.get(myParent).to({__frame:65}, 1500).call(myParent.resetPulse);
                tween.addEventListener("change", function() {
                myParent.gotoAndStop(myParent.__frame);
                });
            }
        }

        myParent.resetPulse = function() {
            myParent.gotoAndStop(1);
            myParent.isPulsing = false;
        }

        myParent.callRandomPulse = function() {
            var ran = Math.random();

            if (ran < freqNumber) {
                myParent.pulse();
            }
        }

        createjs.Ticker.addEventListener("tick", myParent.callRandomPulse);
    }
}

发生的情况是只有最后一个脉冲星有动画(无论组中有多少).我想知道是不是因为只附加了一个事件侦听器?或者不知何故所有的听众都被添加到一个脉冲星"中?请帮忙!

What happens is that only the last pulsar animates (no matter how many are in the group). I'm wondering if it's because only one event listener is being attached? Or somehow all the listeners are being added to one 'pulsar'? Please help!

成功!感谢 Robert(以及 Bergi 对类似问题的链接),帮助我更多地了解了关于关闭和解除绑定传递给函数的变量的知识 - 正如另一个线程上的链接所说:

Success! Thanks to Robert (and also Bergi's link to the similar issue), I was helped to understand a little more about closure and unbinding the variable being passed into the function - as the link on the other thread says:

"如果我们传递一个参数,[the] 函数会制作它自己的本地副本变量(如果不是通过引用传递的对象类型)"

"if we pass a parameter [the] function makes its own local copy of the variable (if it is not object type which pass by reference)"

这允许每个脉冲星对它的父级有一个离散的引用,正如 myParent 的每次迭代所定义的那样,而不是由 的最终值持有的单个外部范围引用我的父母.(@Robert Koritnik 如果我有误解或不正确,请告诉我!感谢您的帮助,如果我对这个网站不熟悉,我会 +1.很快,希望)>

This allows each pulsar to have a discrete reference to its parent as defined by each iteration of myParent, rather than the single outer-scope reference that was being held by the final value of myParent. (@Robert Koritnik please let me know if I have misunderstood or this is incorrect! Thanks for your help, I would +1 if I wasn't so new to the site. Soon, hopefully)

推荐答案

您遇到的问题是您在迭代脉冲星的过程中不断增加 i 并添加这些事件侦听器.因此,当您的列表器实际触发时,他们使用 myParent(注意您可能的错字,有时在它前面使用下划线,有时不使用)变量,该变量在您的 for 循环完成时最后设置为最后一个脉冲星(最后一个值i);

The problem you're having is that you iterate over your pulsars incrementing i along the way and adding those event listeners. So when your listers actually fire, they use myParent (mind your likely typo sometimes using underscore in front of it and sometimes not) variable which was last set to the last pulsar when your for loop completed (last value of i);

您必须更改这段代码

myParent.pulse = function() {
    if (myParent.isPulsing == false) {
        myParent.isPulsing = true;
        myParent.__frame = 1
        var tween = createjs.Tween.get(myParent).to({__frame:65}, 1500).call(myParent.resetPulse);
        tween.addEventListener("change", function() {
            myParent.gotoAndStop(myParent.__frame);
        });
    }
}

为此:

myParent.pulse = (function(parent) {
    return function() {
        if (parent.isPulsing === false) {
            parent.isPulsing = true;
            parent.__frame = 1
            var tween = createjs.Tween.get(parent).to({__frame:65}, 1500).call(parent.resetPulse);
            tween.addEventListener("change", function() {
                parent.gotoAndStop(parent.__frame);
            });
        }
    };
})(myParent);

此更改的作用是创建一个新的函数作用域,捕获 myParent 的当前值并将其存储在局部变量(参数)parent 中,然后返回一个使用它的函数新捕获的价值.

What this change does it creates a new function scope capturing current value of myParent and storing it in local variable (parameter) parent and then returning a function that uses this new captured value.

也许我在这方面捕获的太多了,我应该只为 tween.addEventListener 函数调用创建一个新的函数作用域.您应该知道哪个部分需要捕获.我的代码捕获的代码比可能需要的多得多,因此它应该也能正常工作,但过一段时间当你回到它并引入一些更改时,它可能看起来很混乱.

Maybe I've captured even too much in this and I should only create a new function scope for the tween.addEventListener function call. You should know which part need capturing. My code captures much more code than likely required so it should work just as well, but it may seem confusing after a while when you'll get back to it introducing some change.

因此将范围缩小到最少的语句集,例如:

Therefore reduce scoping to the minimum set of statements like:

myParent.pulse = function() {
    if (myParent.isPulsing == false) {
        myParent.isPulsing = true;
        myParent.__frame = 1
        var tween = createjs.Tween
            .get(myParent)
            .to({__frame:65}, 1500)
            .call(myParent.resetPulse);
        tween.addEventListener("change", (function(parent) {
            return function() {
                parent.gotoAndStop(parent.__frame);
            };
        })(myParent));
    }
}

但如前所述,这可能不起作用,因为它使用最后一个 myParent 脉冲实例的 __frame 变量.所以你最终可能会改变我的第一个代码.

But as mentioned this may not work as it uses __frame variable of the last myParent pulse instance. So you may end up with my first code change.

这篇关于JavaScript 中的范围(我认为?!)挑战的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆