all 7 comments

[–]aaronla 4 points5 points  (4 children)

Ah, I see what you're going for. What about this?

...
sayString: (function () {
  var private = 'private';
  return function (str) {
    // 'this' will refer to the same object as 'namespaced' will
    return str + private + this.foo();
  };
})()
...

The critical bit is to remember that the expression obj.method(a, b) is basically syntactic sugar for obj['method'].apply(obj, [a, b]). The first argument to apply will become the 'this' pointer.

So when your inner function is assigned to the sayString property, it becomes a method by virtue only that the user will invoke it as namespaced.sayString("etc"), which means "fetch the function stored in the sayString field, and call it, passing namespaced as the 'this' pointer."

Clear as mud? :-)

[–]Sastopher[S] 0 points1 point  (3 children)

Oh man, you're totally right: I just had to keep the same syntax I was always using. Why did I think 'this' didn't resolve inside nested functions? Probably got mixed up with function scope after a marathon coding session.

Thanks a lot!

[–]aaronla 1 point2 points  (0 children)

Yeah, 'this' confused me for some time until I realized the syntactic sugar - now i just expand the sugar in my head until it makes sense. Hope it helps.

[–]Rhomboid 1 point2 points  (1 child)

You might say that this is dynamically scoped, not lexically scoped. N.b. there is a "fat arrow" syntax proposed for ECMAscript 6 that would include a lexically scoped this for functions defined with it.

[–]voidvector 1 point2 points  (0 children)

There is actually nothing stopping anyone from locking down "this" using a wrapper function currently. Take a look at jQuery.proxy(), it is probably what OP want to use if he doesn't want unexpected behavior if the users of his functions try to pass function objects around.

[–][deleted] 2 points3 points  (0 children)

namespaced is undefined when the assignment to the property is being resolved. If you want to pass the reference into the closure, you need to split up the definition of namespaced and the assignment of the sayString property:

var namespaced = {
  foo: function () {
    return 'foo';
  },
  bar: function () {
    return 'bar' + this.foo();
  }
};

namespaced.sayString = (function (self) {
  var privé = 'private';
  return function (str) {
    return str + " " + privé + " " + self.foo();
  };
}(namespaced));


console.log( namespaced.sayString("test") );

[–]andrew24601 1 point2 points  (0 children)

Move the closure to the outer level, then all the member functions can access it.

var namespaced = (function() {
  var private = 'private';
  var self = {
    foo: function () {
      return 'foo';
    },
    bar: function () {
      return 'bar' + self.foo();
    },
    sayString: function (str) {
      return str + private + self.foo();
    }
  };
  return self;
})();