Javascript - 从子对象访问'this'成员

时间:2012-02-13 04:50:24

标签: javascript prototype

在一个对象中,仅仅出于纯粹的美学原因,我想知道是否有办法允许从子对象中访问“this”成员。

以这个例子(我在http://jsfiddle.net/Wzq7W/5/处反映):

function BlahObj() {
    this.users = {};
}
BlahObj.prototype = {
    userGet: function(id) {
        if (this.users[id] !== undefined) {
            return this.users[id];
        }
    },
    userAdd: function(id, name) {
        if (this.users[id] === undefined) {
            this.users[id] = name;
        }
    },
    user: {
        get: function(id) {
            if (this.users[id] !== undefined) {
                return this.users[id];
            }
        }
    }
}

var test = new BlahObj();
test.userAdd(1, 'User A');
test.userAdd(2, 'User B');
test.userAdd(3, 'User C');
test.userGet(2);
test.user.get(1);

userGet()方法将正确返回“用户B”,但由于范围,user.get()无法访问基本成员。

在上下文中,这个对象会有更多的成员和方法,所以骆驼套管看起来很脏;能够通过组(user.get(),queue.foo(),room.data())将它们分开似乎是理论上更好的方法。这是实用的吗?有没有办法按照我想要的方式做我正在问的问题,或者我会用camelCase做得更好?

感谢您的想法!

3 个答案:

答案 0 :(得分:3)

  

userGet()方法将正确返回“用户B”,但由于范围,user.get()无法访问基本成员。

函数的this关键字的值与范围无关。在函数中,this是一个局部变量,其值由调用设置,而不是如何声明或初始化函数。

您可以使用ES5 bind更改它(并为那些没有它的环境添加Function.prototype.bind),或者您可以使用闭包或类似策略而不是this

修改

考虑使用camelCase选项,我认为它比创建子级别更清晰,即

getUser: function() {...},
addUser: function() {...},
...

而不是:

user: {
  get: function(){},
  add: function(){},
  ...
}

输入的字符数也少一个(例如addUser vs user.add

答案 1 :(得分:3)

DEMO

改变这个:

user: {
    get: function(id) {
        if (this.users[id] !== undefined) {
            return this.users[id];
        }
    }
}

要:

user: function() {
    var that = this;

    return {
        get: function(id) {
            if (that.users[id] !== undefined) {
                return that.users[id];
            }
        }
    };
}

您必须将其称为test.user().get(1),而不是test.user.get(1),而不是

答案 2 :(得分:0)

我的另一位朋友建议在构造函数中使用bind()类似于@RobG和@Twisol所建议的循环,但不必专门写出每一行。

可能有其他方法可以执行该循环,因此它并不特定于两个级别,但现在这可能已经足够好了。是否有任何我应该注意的含义,特别是性能,或者我可能没有考虑的其他考虑因素?

function BlahObj() {
    this.users = {};

    for (sub in this) {
        for (key in this[sub]) {
            if (typeof this[sub][key] == 'function') {
                this[sub][key] = this[sub][key].bind(this);
            }
        }
    }
}
BlahObj.prototype = {
    userGet: function(id) {
        if (this.users[id] !== undefined) {
            return this.users[id];
        }
    },
    userAdd: function(id, name) {
        if (this.users[id] === undefined) {
            this.users[id] = name;
        }
    },
    user: {
        get: function(id) {
            if (this.users[id] !== undefined) {
                return this.users[id];
            }
        }
    }
}

var test = new BlahObj();
test.userAdd(1, 'User A');
test.userAdd(2, 'User B');
test.userAdd(3, 'User C');
test.userGet(2);
test.user.get(1);