Смена контекста callback без его явного изменения

Рейтинг: 1Ответов: 1Опубликовано: 03.09.2014

Я всегда думал, что контекст метода меняется только тогда, когда его явно подменяем при помощи методов call или apply. Но сейчас на деле я узнал, что меняется он всегда. Это так или у меня что-то сломалось?
Для примера: если взять callback и передать его в другой объект, то при вызове callback() меняется и его контекст.

И если это так и должно быть, то единственным и верным решением так и остается биндинг в конструкторе?

Дополнение:

function EventDispatcher(target){
    this.target = target;
}

EventDispatcher.prototype = {
    callback: undefined,
    addEventListener: function(callback){
        this.callback = callback;
    },
    dispatchEvent: function(args){
        this.callback(args);
    },
    toString: function(){
        return '[object EventDispatcher]';
    }
};

function Two(){
    EventDispatcher.call(this, this);
}

Two.prototype = Object.create(EventDispatcher.prototype);
Two.prototype.constructor = Two;

Two.prototype.toString = function(){
    return '[object Two]';
}

function Three(two){
    this.two = two;
    this.two.addEventListener(this.handler);

}

Three.prototype.toString = function(){
    return '[object Three]';
}

Three.prototype.handler = function(args){
    console.log('[object Three] => handler', args, this.toString());
}

var two = new Two();
var three = new Three(two);

two.dispatchEvent('good'); // [object Three] => handler good [object Two]
// как видно, обработчик находится в контексте [object Two]
// и как теперь передать свойства из события я не знаю, так как this уже не то...

jsfiddle.net

Ответы

▲ 1Принят

Вы явно указали контекст two для метода addEventListener() здесь:

 this.two.addEventListener(this.handler);

Что тут ещё ожидать.

А ещё вы вызвали из two addEventListener с хэндлером из Three, т.е. объект two в результате изменился, потому что вы вызвали addEventListener объекта two, у него this - two.

 otherObject.object.method()
               /|\
                |____this в method

http://jsfiddle.net/oceog/w3s22m6t/

Другими словами, если раскрыть скобки, то вы написали

two.callback=three.handler

Такая запись вам понятна?