Let's say I have this code
(function() {
function Foo(arg) {
this.name = arg;
}
Foo.prototype = {
bar: {
baz: function() {
alert(this.name); // Undefined...
}
}
}
var foo = function(arg) {
return new Foo(arg);
};
window.foo = foo;
return foo;
}());
foo("Anything").bar.baz();
How can I make "this" in my function "baz" refers to the object Foo without using bind or apply when I call it from outside ?
FWIW, I would strongly recommend not building nested structures like that, or at least not on the prototype, because the bar object is shared amongst all of the instances, which opens the door to a lot of cross-talk-style bugs. Instead, I'd create bar within the constructor.
How can I make "this" in my function "baz" refers to the object Foo without using bind or apply when I call it from outside ?
You may have bind and apply/call slightly confused. You wouldn't use bind when calling the function, but when creating it. Unless you use bind (or something equivalent to it), you can't do what you've said you want, because absent bind (or similar), this is set by how the function is called, and so this.bar.baz() will make this be this.bar within the call.
Here's how you'd build bar within the constructor, and use bind to make baz use the correct this:
function Foo(arg) {
this.name = arg;
this.bar = {
baz: function() {
alert(this.name);
}.bind(this) // <== Note
};
}
Example:
function Foo(arg) {
this.name = arg;
this.bar = {
baz: function() {
snippet.log(this.name);
}.bind(this) // <== Note
};
}
var f1 = new Foo("f1");
var f2 = new Foo("f2");
f1.bar.baz(); // "f1"
f2.bar.baz(); // "f2"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
More about cross-talk: The naive thing to do is to just add one line to your Foo constructor, and keep bar on the prototype:
this.bar.baz = this.bar.baz.bind(this);
That would be a very bad idea, because you'd get cross-talk between instances:
function Foo(arg) {
this.name = arg;
this.bar.baz = this.bar.baz.bind(this); // DON'T DO THIS
}
Foo.prototype = {
bar: {
baz: function() {
snippet.log(this.name);
}
}
};
var f1 = new Foo("f1");
var f2 = new Foo("f2");
f2.bar.baz(); // "f1" -- cross talk! Should be f2
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Use bind at declaration time to properly scope this, e.g.
function foo() {}.bind(this);
Related
How can I access baz() from inside the bar() function in the following code?
var obj = {
baz : function(){ alert("Hi!"); },
foo: {
bar: function(){
baz();
}
}
}
JavaScript doesn't have kind of a built-in parent reference because an object can be referenced by multiple 'parents' in what we call a many-to-one relationship.
As others have said, in this simplified case, simply calling obj.baz() will work.
In a more complicated case, you would have to manually build the object and track parenthood:
// Create the root object
var rootObject = {baz: function() {console.log('rootBaz');}}
// And the basic child
var childObject = {foo: function() {console.log('childFoo');}}
// Configure the parent
childObject.parent = rootObject;
// Add our call.
childObject.baz = function() {this.parent.baz()};
// Invoke and test
childObject.baz();
Which can be slightly simplified:
var rootObject = {
baz: function() {console.log('rootBaz');}
};
var childObject = {
foo: function() {console.log('childFoo');},
baz: function() {this.parent.baz()}
};
childObject.parent = rootObject;
childObject.baz();
Updated per Sujet's comment
In addition, if you need to make sure that baz has the correct value for this you can use either call or apply.
baz: function() {this.parent.baz.call(this.parent)}
If your code doesn't require this then I would recommend a straight function call per my original answer.
Just use the object reference:
var obj = {
baz : function(){ alert("Hi!"); },
foo: {
bar: function(){
obj.baz();
}
}
}
You need to reference via object.property notation.
In your example you would get baz via:
obj.baz()
Some great resources for this:
http://www.w3schools.com/js/js_objects.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
I have an object literal as follows. In the Init method I set a handler for a click event. Later, when the handler is called, I want to access the Bar property using this keyword. At that point, this has the jQuery meaning.
Also, to make things clear, I don't want to implement functions inline with the selectors.
var StackOver = {
Bar: "MyBarValue",
Init: function(){
$("#postId").click(this.Foo);
},
Foo: function(eventObject){
// here **this** is jQuery keyword
// how do I access StackOver.Bar?
}
}
How do I access properties of this object literal inside Foo?
This could have been easy if I was using a constructor literal, which is not a go for me:
var StackOver = function (){
var self = this;
function bar()
{
// I can use self here
}
}
edit I forgot to mention that I use the Revealing Module Pattern in this object literal, that hides private properties from the object.
Everyone else is suggesting .bind, which makes sense, but you also may just be able to reference the object itself in the closure:
Foo: function(eventObject) {
console.log(StackOver.Bar);
}
one option:
Init: function(){
$("#postId").click(this.Foo.bind(this));
}
another option: (from http://api.jquery.com/jquery.proxy/)
Init: function(){
$("#postId").click($.proxy(this.Foo, this));
}
both of there take the this variable so you can't use this for other purposes
if, however, you can't use this:
Init: function(){
$("#postId").click(function (self) {
return function (event) {
return self.Foo(self, event);
}
}(this));
}
and in Foo just add the self parameter.
Foo: function (self, event...) {
...
}
All that said, why can't you use (function () {var self = this; ... }()) ?
It is the revealing module pattern, after all
var StackOver = {
/*...*/
Init: function(){
$("#postId").click(this.Foo.bind(this));
},
/*...*/
Foo: function(eventObject){
// here **this** was actually the html element
// now it's the old this.
alert(this.Bar);
}
}
I'm not sure why this has to be an object literal. If you can use other structures, you could gain access through a revealing module like this:
var StackOver = (function() {
var bar = "MyBarValue",
init = function(){
$("#postId").click(foo);
},
foo = function(eventObject) {
// here `this` might be a jQuery wrapper object
// but you can access `bar` directly.
};
return {
Bar: bar, // Or not. Do you really want this public?
Init: init,
Foo: foo
}
}())
Consider the Following Example
var Foo = function(){
this.identity = 'Foo';
};
Foo.prototype.bar = function(){
this.identity = 'bar';
};
var fooInstance = new Foo(),
bar = new fooInstance.bar();
Question
Within bar, how may I obtain the fooInstance variable? Is there a way for a child of Foo to recognize its parent as fooInstance? For example, how could I create a function in bar that would return fooInstance. A slight caveat is that bar must by created using the prototype command and cannot simply be nested in Foo to access any Foo instances that way.
My Ideas and Why They Don't Work
It would be possible to rewrite the functions like so
var Foo = function(){
this.identity = 'Foo';
};
Foo.prototype.createBar = function(){
var parent = this;
function bar(){
this.parent = parent;
this.identity = 'bar';
};
return new bar();
};
var fooInstance = new Foo(),
bar = fooInstance.createBar();
Yet for the purposes of creating easily readable code i would rather not use this approach if not needed.
Further Clarification
Let me put the question in context. I am prototyping on CanvasRenderingContext2D so that all contexts for the canvas element will contain my new method. Lets call that method foo and assume context is a created canvas context. How create a variable like so "new context.foo()" such that the foo function can use the context variable?
If you need to reference the fooInstance object from the bar object, you could use dependency injection like this:
Foo.prototype.bar = function(fooInstance) {
this.identity = 'bar';
this.fooInstance = fooInstance;
};
var fooInstance = new Foo(),
bar = new foo.bar(fooInstance);
You could simplify the creation process by implementing a factory function on Foo.
Foo.prototype.createBar = (function() {
function Bar(parent){
this.parent = parent;
this.identity = 'bar';
};
return function () {
return new Bar(this);
};
})();
var fooInstance = new Foo(),
bar = fooInstance.createBar();
how could I create a function in bar that would return fooInstance
If that function is called as a constructor (with new), you can't really do it. The this keyword, the only reference to the "parent" (the object on which you called the method) is set to the new instance in a constructor invocation. You can get the reference only with a closure, for example by creating the constructor in the parent's constructor function (which doesn't work for you) or by returning the constructor from a closure on the prototype (which you nearly got in the second example):
Foo.prototype.getBarCoonstructor = function() {
var parentFoo = this;
return function Bar() {
// constructor things
// using "parentFoo" reference
};
};
// Usage:
var bar = new (foo.getBarConstructor()) (); // ugly.
Instead of creating new constructors for every call of getBarConstructor, you better should put it outside of the method and put parentFoo as an argument to it. Your idea was already quite good.
function Bar(parent) {
// constructor things, referring "parent"
}
Bar.prototype.… = …;
Foo.prototype.createBar = function() {
return new Bar(this); // passing the Foo instance
};
(#plalx has the same solution, but wrapped in a module closure)
Foo.prototype.bar is simply a function on the prototype Object of Foo. There is no way for that function to know of its 'parent' unless you explicitly define it in its scope chain.
I.e. if you would do
var Foo = function(){
this.identity = 'Foo';
};
var fooInstance = new Foo();
Foo.prototype.bar = function(){
console.log(fooInstance); // retrieve from scope
this.identity = 'bar';
};
bar = new foo.bar();
that would work.
Is this even possible?
function foo() {
// do stuff
}
foo.prototype = {
// stuff...
bar: function() {
// do some things with this, where this refers to foo
},
bar.prototype: {
// set some definitions for bar to work with.
// Where does "this" go and what does it refer to?
}
}
No. You'd need to use
function bar() {...}
bar.prototype = {...};
function foo() {...}
foo.prototype.bar = bar;
Although this won't work. There is no reason to put the bar constructor on foos prototype, because when instantiating bar objects by using new ((new foo()).bar)(), there will be no reference to the foo instance. You could equally use new foo.prototype.bar().
In example:
function foo() {
var bar = this.bar = function () {
return "bar";
};
this.mybar = function () {
return bar();
}
}
var myFoo = new foo();
myFoo.bar = function() {
return "notbar";
};
myFoo.bar(); // returns 'notbar'
myFoo.mybar(); // returns "bar"
Basically it allows for an internal private method to a closure, with the possibility of being overwritten only for external access. So the reference to the original function never changes, for references of that function within the closure. But instantiators of the closure object can overwrite that function without breaking the functionality of the object.
Is there a name for this particular construct, and is it even useful?
If you refer to assigning a function to a local variable and using this function in another public method, then yes, this would some form of data encapsulation. Apart from that, I'd say there is not special name for that.
var bar is a variable local to the function and this.bar is a property of the new object. The variable and the property happen to have the same name, but they are not related.
It is only useful if you want to make the function in bar publicly accessible and ensure the correct working of the other function, in case the public bar is overwritten.
So it is some form of protecting the other functions, but it is not a special pattern to allow external overwriting.
If the sole purpose of this.bar is to be overwritten, then you'd achieve the same with:
function foo() {
var bar = function () {
return "bar";
};
this.mybar = function () {
return bar();
}
}
var myFoo = new foo();
myFoo.bar = function() {
return "notbar";
};
myFoo.bar(); // returns 'notbar'
myFoo.mybar(); // returns "bar"
Of course, if you call myFoo.bar() before you assign a function to it, then you will get an error.