In an object, for nothing more than purely aesthetic reasons, I'm wondering if there's a way to allow access to 'this' members from within sub-objects.
Take this example (which I've mirrored at 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);
The userGet() method will properly return 'User B', but due to scope, user.get() cannot access the base member.
In context, this object will have many more members and methods that go along with it, so camel-casing seems so dirty; being able to separate them out by group (user.get(), queue.foo(), room.data()) seems like a better approach in theory. Is it practical? Is there a way to do what I'm asking, in the way I'm looking to do it, or would I just be better off with camelCase?
Thanks for your thoughts!
The userGet() method will properly return 'User B', but due to scope, user.get() cannot access the base member.
The value of a function's this
key word has nothing to do with scope. In a function, this
is a local variable whose value is set by the call, not by how the function is declared or initialised.
You can use ES5 bind to change that (and add Function.prototype.bind for those environments that don't have it), or you can use a closure or similar strategy instead of this
.
Consider the camelCase option instead, I think it's much cleaner than creating a sub–level, ie
getUser: function() {...},
addUser: function() {...},
...
rather than:
user: {
get: function(){},
add: function(){},
...
}
It's one character less to type too (eg addUser
vs user.add
)
Change this:
user: {
get: function(id) {
if (this.users[id] !== undefined) {
return this.users[id];
}
}
}
To:
user: function() {
var that = this;
return {
get: function(id) {
if (that.users[id] !== undefined) {
return that.users[id];
}
}
};
}
You have to call it like test.user().get(1)
instead of test.user.get(1)
though
Another friend of mine suggested a loop in the constructor that would bind() similar to what both @RobG and @Twisol had suggested, but without having to specifically write out each line.
There are probably other ways to do that loop so it's not specific to two levels deep, but this might be good enough for now. Are there any implications I should be aware of, specifically performance, or other considerations I may not be taking into account?
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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.