Вызов функции объекта из события onload приводит к потере контекста. - PullRequest
2 голосов
/ 14 марта 2012

Я хотел вызвать функцию, когда все необходимые изображения загружены.Количество изображений известно заранее, поэтому я попытался присоединить вызов функции к событию onload каждого изображения и подсчитать, сколько раз оно было вызвано.

<html>

<head>
    <script>

    var tractor;

    function Tractor()
    {
        this.init_graphics();
    }

    Tractor.prototype.init_graphics = function()
    {
        this.gr_max = 3;
        this.load_count = 0;

        this.loading_complete(); // #1 test call, works OK

        this.img1 = new Image();
        this.img1.onload = this.loading_complete; // #2 gets called, but gr_max = undefined, load_count = NaN
        this.img1.src = "http://dl.dropbox.com/u/217824/tmp/rearwheel.gif"; //just a test image
    }

    Tractor.prototype.loading_complete = function()
    {
        this.load_count += 1;
        alert("this.loading_complete, load_count = " + this.load_count + ", gr_max = " + this.gr_max);
        if(this.load_count >= this.gr_max) {this.proceed();}
    };

    function start()
    {
        tractor = new Tractor();
    }
    </script>
</head>

<body onload="start();">
</body>

</html>

Когда оно просто вызывается из другой функцииобъект (см. # 1), он работает так, как я ожидал.Однако, когда он вызывается из события onload (см. # 2), переменные становятся «неопределенными» или «NaN» или что-то в этом роде.Что происходит?Что я делаю неправильно?Как мне заставить это работать?

Я не помню, чтобы когда-либо создавал свои собственные объекты в Javascript, поэтому я, безусловно, глубоко извиняюсь за этот вопрос "что не так с моим кодом".Я использовал эту статью в качестве ссылки, в основном раздел 1.2.

На всякий случай я поставил тот же код на http://jsfiddle.net/ffJLn/

Ответы [ 3 ]

7 голосов
/ 14 марта 2012

bind контекст для обратного вызова:

this.img1.onload = this.loading_complete.bind(this);

См .: http://jsfiddle.net/ffJLn/1/ (так же, как у вас, но с этим дополнением)

Вот подробное объяснение того, как bind работает: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Основная идея состоит в том, что в связанной функции this равно тому, что вы передаете в качестве параметра bind.

Другой вариант - создать замыкание:

var self = this;
this.img1.onload = function() { self.loading_complete() };

Замыкания - это функции, которые хранят ссылки на свой контекст (фактически, все функции в javascript работают таким образом). Итак, здесь вы создаете анонимную функцию, которая сохраняет ссылку на self. Так что это еще один способ сохранить контекст и для loading_complete иметь право this.

См .: http://jsfiddle.net/ffJLn/2/ (так же, как у вас, но со второй возможностью)

2 голосов
/ 14 марта 2012

Когда вызывается # 2, ваш this изменился.this теперь относится к new Image(), а не к Tractor объекту.

Попробуйте изменить ...

this.img1.onload = this.loading_complete;

на

var that = this;
this.img1.onload = function() { that.loading_complete(); };
0 голосов
/ 01 января 2019

Теперь вы можете использовать функции стрелок es6, которые обеспечивают лексическое связывание :

this.img1.onload = () => { this.loading_complete(); };

...