为对象内的对象分配回调

时间:2014-01-29 06:19:01

标签: javascript

我正在尝试重构一段代码,这些代码通过将变量名称及其相应的回调放入一个易于迭代的对象中,对variables数组中的每个变量起作用。问题是变量[0] .callback在调用Foo.bar(data)时结束undefined。整个对象的功能需要保留在对象本身中。

到目前为止,我唯一的解决方案是在将函数分配给回调变量时定义函数,但这不太理想,因为回调本身无法访问所需的变量。

...
{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

3 个答案:

答案 0 :(得分: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});

答案 1 :(得分:2)

回答comment
不,我不确定我能说得好,但还是试试。 因此,this是函数的关键字,其值取决于它使用的上下文,并且在严格模式和非严格模式之间也存在一些差异。

如果在全局上下文this中使用它将以严格和非严格模式引用窗口对象。
严格模式

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

非严格模式

console.log(this); // window

如果它在Function上下文中使用,则该值可能与调用此函数的位置不同,如果从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
};

因为,您可以使用new运算符作为构造函数调用函数,在这种情况下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";

此外,您可以将明确thisFunction.prototype.callFunction.prototype.applyFunciton.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

答案 2 :(得分: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"