2014-01-29 5 views
2

Я пытаюсь реорганизовать кусок кода, который действует на каждую переменную, найденную в массиве variables, путем добавления имени переменной и соответствующего обратного вызова в объект, который легко повторяется. Проблема в том, что переменные [0] .callback заканчиваются undefined при вызове Foo.bar (data). Функциональность всего объекта должна оставаться в самом объекте.Назначение обратного вызова объекту внутри объекта

До сих пор мое единственное решение заключалось в том, чтобы определить функции, когда они назначены переменным обратного вызова, но это не так идеально, потому что сами обратные вызовы не могут получить доступ к требуемым переменным.

... 
{name: "x", callback: function() {...}}, 
... 

Желаемая Функциональность:

console.log(Foo.variables[0].callback != undefined) //true 
Foo.bar(); //Will print "y" 

Я пропускаю что-то глупо? Или я должен использовать другой шаблон для решения этой конкретной проблемы?

Спасибо за помощь!

var Foo = { 

    variables: [ 
     {name: "x", callback: this.funX}, 
     {name: "y", callback: this.funY}, 
     {name: "z", callback: this.funZ} 
    ], 


    //For this example, data could be the following object 
    // data = {x: 0, y: 1, z: 0}; 
    bar: function(data) { 

     this.variables.forEach(function(elem) { 
      if(data[elem.name] == 1) 
       elem.callback(); 
     }); 

    }, 

    funX: function() { 
     console.log(this.variables[0].name); 
    }, 

    funY: function() { 
     console.log(this.variables[1].name); 
    }, 

    funZ: function() { 
     console.log(this.variables[2].name); 
    } 
} 

Несколько актуальны:

javascript: call function inside object, from a callback function

+0

@CoryDanielson - Мои извинения - я буду править пост и сделать его более четким. В то же время я хочу вызвать Foo.bar (data) и иметь консоль.log («y»). – TMan

+1

Хмм, я собираюсь сделать быструю скрипку. Я думаю, что получаю то, что вы просите –

+0

Вы неправильно поняли, как это работает в JavaScript. [MDN this - JavaScript] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) – Givi

ответ

3

LIVE DEMO

Отказываем:

//For this example, data could be the following object 
// data = {x: 0, y: 1, z: 0}; 

так что давайте идти с Foo.bar({x: 0, y: 1, z: 0});

Например:

var Foo = { 

    variables: [ 
     {name: "x", callback: "funX"}, 
     {name: "y", callback: "funY"}, 
     {name: "z", callback: "funZ"} 
    ], 
    bar: function(data) { 
     var that = this;    // this (Foo) reference! 
     that.variables.forEach(function(el, i, arr) { 
      if(data[el.name] == 1){ 
      var fn = arr[i].callback; // funY 
      that[fn]();  // "y" (cause that's exactly what funY does!!) 
      } 
     }); 
    }, 
    funX: function() { 
     console.log(this.variables[0].name); 
    }, 
    funY: function() { 
     console.log(this.variables[1].name); 
    }, 
    funZ: function() { 
     console.log(this.variables[2].name); 
    } 
}; 


Foo.bar({x: 0, y: 1, z: 0}); 
+0

Awesome, спасибо! Считается ли плохой практикой называть вещи из 'окна' напрямую? Если да, то есть ли способ сделать эту работу так, если бы «Foo» было названо чем-то другим, все будет работать без заминки? – TMan

+1

@TMan, если вам не нравится вызов объекта 'window'(), чем не использовать его, создайте перед вашим forEach ссылку на объект' this' ('Foo') и используйте его вместо' window ':) - отредактировал мой ответ соответственно –

+1

Ха-ха блестящий! Благодаря! – TMan

1

Вы хотите использовать другой шаблон. JS в эти дни стало довольно сложным, и есть много преимуществ объектно-ориентированной. Это делает объем недвусмысленным, а порядок исполнения - менее изящным.

В то время как вы могли бы получить больше работать, лучше реализация будет выглядеть примерно так:

var Foo = function() { 
    // you can replace the anonymous functions with references if you like 
    this.variables = [ 
    'x': new Variable('x', function() { console.log('x something'); }), 
    'y': new Variable('y', function() { console.log('y something'); }), 
    'z': new Variable('z', function() { console.log('z something'); }) 
    ] 
}; 

// Now data can be like this: ['x', 'y'] // much clearer! 
Foo.prototype.bar = function(data) { 
    data.forEach(function(symbol) { 
    var variable = this.variables[symbol]; 
    if (variable) 
     variable.callback.apply(this); // much safer! 
    }, this); 
}; 

// A better labeled pair. 
var Variable = function(name, callback) { 
    this.name = name; 
    this.callback = callback; 
}; 

Пример использования может выглядеть примерно так:

var foo = new Foo(); 
foo.bar(['x']);  // "x something" 
foo.bar(['y', 'z']) // "y something" \ "z something" 
+0

Спасибо за ответ @adu - будет ли это работать, если я хочу определить обратные вызовы вне назначения? Например, я могу получить исходный код выше работы, определив функции inline, как и в примере, который вы указали. Немного другая нота, но мне сказали несколько месяцев назад, что прототипы были немного старыми, из-за отсутствия лучшего термина, и другие предпочтения были предпочтительнее. Разве это не так? – TMan

+1

Да, они все равно будут работать. Дайте мне знать, если вы хотите пример. Фактическое ключевое слово 'prototype' выходит из стиля. Но это связано с тем, что рамки, такие как BackboneJS, Ember и язык CoffeeScript, становятся все более распространенными. Они немного тяжелы для вашего вопроса, но все они объектно ориентированы! – adu

2

Ответ на comment
Нет, я не уверен, что я мог бы объяснить, хорошо, но все-таки попробовать. Итак, this является ключевым словом функции, его значение зависит от того, в каком контексте оно используется, а также имеет некоторые различия между строгим режимом и нестрогим режимом.

Если он используется в глобальном контексте this будет ссылаться на объект окна в строгом и нестрогом режиме.
Режим Strict:

"use strict"; 
console.log(this); // window 

нестрогого режима:

console.log(this); // window 

Если он используется в контексте функции значение может быть, отличается от того, где вызывается эта функция, если она вызывается из Global контекст его будет ссылаться на объект окна в нестрогом режиме и не определен в строгом режиме.

Режим Строгий:

(function() { 
    "use strict"; 
    console.log(this); // undefined 
}()); 

нестрогих режим:

(function() { 
    console.log(this); // window 
}()); 

Когда функция вызывается как метод объекта, его this устанавливается на объекте метод.
Таким образом, в вашем случае:

var Foo = { 
    /* ... */ 
    bar: function(data) { 
     // this refer to `Foo` 
     this.variables.forEach(function(elem) { 
      // but, here `this` refer to window in non-strict mode and undefined in strict mode 
      if(data[elem.name] == 1) 
       elem.callback(); 
     }); 

    }/*, ... */ 
}; 

и, если ваш объект Foo объявляется в глобальном контексте его будет ссылаться на объект окна в строгом режиме и в нестрогой режиме слишком:

var Foo = { 
    variables: [ 
     {name: "x", callback: this.funX}, // this === window 
     {name: "y", callback: this.funY}, // same 
     {name: "z", callback: this.funZ} // ... 
    ]/*, ... */ 
}; 

, но, если он объявлен в области видимости функции и функции вызываются из глобального контекста:

function myFunction() { 
    var Foo = { 
     variables: [ 
      // this will refer to window in non-strict mode and undefined in strict mode 
      {name: "x", callback: this.funX}/*, ... */    
     ]/*, ... */ 
    }; 
} 
myFunction(); 

, но, если это метод объекта, и нет никакой разницы, в каком контексте является объектом объявлен:

var myObj = { 
    myMethod : myFunction // now this will refer to myObj 
}; 

Так, вы можете вызвать функцию в качестве конструктора с новым оператором, в таком случае this будет обратитесь к экземпляру этого конструктора (класса), и нет никакой разницы между строгим или нестрогим режимом.

function MyClass(v) { 
    this.myProp = v; // this will refer to instances of MyClass 
} 
var myClass1 = new MyClass("some value"); 
var myClass2 = new MyClass("other value"); 

console.log(myClass1.myProp); // "some value"; 
console.log(myClass2.myProp); // "other value"; 

Кроме того, вы можете связать this с явной форме Function.prototype.call, Function.prototype.apply и Funciton.prototype.bind

var myObj = { 
    x: 5, 
    y: 6 
}; 

function sum() { 
    return this.x + this.y; 
} 

console.log(sum.call(myObj)); // 11 
console.log(sum.apply(myObj)); // 11 
console.log(sum.bind(myObj)()); // 11 
+0

* Мое субъективное мнение: используйте ключевое слово 'this' в контексте функции и только когда это метод объекта или конструктор. * – Givi

+1

Удивительное объяснение, спасибо! – TMan

Смежные вопросы