Javascript: Как объект может хранить ссылку на метод другого объекта и вызывать его «удаленно»? - PullRequest
3 голосов
/ 22 мая 2011

Итак, я получил два объекта, а и б. Теперь я хочу передать один из методов b объекту a, который должен его сохранить. Давайте назовем этот метод b.met:

b.met=function(){
    alert(this.txt);
}

Теперь я хочу позвонить б.мету из а. Следующий код не работает, так как a.met является клоном b.met внутри области действия a:

a.met=b.met;
a.met(); //Executes in the 'a' scope!

К настоящему времени я нашел единственный способ сохранить имя метода в строке и использовать его в операторе eval:

a.toCall='b.met';
eval(a.toCall+'();');

Поскольку все говорят, что вам следует избегать использования eval ... какие еще есть возможности?


РЕДАКТИРОВАТЬ - см. В комментариях: поэтому я изменил свой код с:

a:{
    processes:[],
    spawnProcess:function(type,id,closeFn){
    var closeFn=closeFn || 'function(){}';
    this.processes.push({type:type,id:id,closeFn:closeFn});
}

до:

a:{
    processes:[],
    spawnProcess:function(type,id,closeFn){
    var closeFn=function(){closeFn()} || 'function(){}';
    this.processes.push({type:type,id:id,closeFn:function(){closeFn()}});
}

При выполнении следующего кода я получаю слишком много ошибок рекурсии:

a.spawnProcess('','',b.met);
a.processes[0].closeFn();

Ответы [ 3 ]

7 голосов
/ 22 мая 2011

Ваше хранение ссылки на функцию.Функция - это просто функция.Это определение для this, основанное на контексте вызова.

Так что если вы храните a.met = b.met и затем вызываете a.met() внутри этой функции this === a

Прочитайте в саду JavaScript о this

То, что вы хотите сделать, это сохранить функцию и контекст для ее вызова.

Это можно сделать как

a.met = function() {
  b.met();
}

или

a.met = b.met.bind(b);

.bind требуется ES5.Рекомендуемые кросс-браузерные альтернативы включают _.bind и $.proxy

Редактировать

Вам необходимо изменить

a.spawnProcess('','',b.met);

до

a.spawnProcess('','', function() {
    b.met();
});

Возможно, вы также захотите это вместо

a: {
    processes: [],
    spawnProcess: function(type, id, closeFn) {
        this.processes.push({
            type: type,
            id: id,
            closeFn: closeFn || function() {}
        });
    }
}
3 голосов
/ 22 мая 2011

Самое простое решение:

a.met = function() { b.met(); };

или использование .bind (см. MDC ), такая же семантика:

a.met = b.met.bind(b);
0 голосов
/ 22 мая 2011

Если у вас много функций и у них есть аргументы, вы также можете сделать это

function B() {
    this.x = "I am b";
}

function A() {
    this.x = "I am A";
}

B.prototype.met = function() {
    alert(this.x);
}

A.prototype.met = B.prototype.met;

Вы можете обновить A.prototype нужными вам функциями из B.prototype.

...