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

#javascript #object #methods #reference #eval

#javascript #объект #методы #ссылка #оценка

Вопрос:

Итак, у меня есть два объекта, a и b . Теперь я хочу передать один из методов 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();
  

Комментарии:

1. Вы ищете apply и call .

Ответ №1:

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

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

Прочитайте в JavaScript garden о 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() {}
        });
    }
}
  

Комментарии:

1. Я еще не пробовал метод .bind, но я попробовал другое решение, которое вы мне дали, и оно не работает для того, что я пытаюсь сделать… Я поместил код в конец своего вопроса, может быть, вы могли бы взглянуть?

2. @Alex кстати, эмуляция процессов в javascript — плохая идея. Используйте web workers. (JavaScript является однопоточным)

Ответ №2:

Простейшее решение:

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

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

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

Ответ №3:

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

 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.