call another function within an object - javascript

After looking through a few different questions regarding this topic, I'm still stumped as to how to access another function from within an object.
window.Think = {
initialize: function(){
this.currentNumber = 0;
},
updateNumber: function(){
this.currentNumber += 1;
},
listener: function(){
document.getElementById('foo').addEventListener('click', function(){
this.parent.updateNumber(); //this is where I want to call the prev function
}
}
The error I'm getting is Cannot call method 'updateNumber' of undefined
How can I call Think.updateNumber() from within listener()?

Callback functions often lose context (context is the value of this). So you have to save the value of this. to a local variable that is shared with the callback function. A common convention for this is var self = this.
listener: function(){
var self = this;
document.getElementById('foo').addEventListener('click', function(){
self.updateNumber();
}
}

this will be rebound to the function's scope. The solution is creating another variable you can refer this to:
listener: function(){
var that = this;
document.getElementById('foo').addEventListener('click', function(){
that.updateNumber();
});
}
Depending on what browsers you are targeting bind might also be a solution:
listener: function(){
document.getElementById('foo').addEventListener('click', function(){
this.updateNumber();
}.bind(this));
}

The problem is that what the keyword "this" represent.
listener: function(){//We call this is function one.
document.getElementById('foo').addEventListener('click', function(){//function two
this.parent.updateNumber(); //this is where I want to call the prev function
}
In function one,"this" represents the object Think.In function two,"this" represents the element foo.So,if you want to call the method updateNumber,you should get the reference to the object Think.We just save the "this" of function one in a variable ,like this:
listener: function(){//We call this is function one.
var outerThis=this;//save Think here.
document.getElementById('foo').addEventListener('click', function(){//function two
outerThis.updateNumber();//use Think.updateNumber here.
}
Now we get the work done. Because in javascript,the function can access it's outer function's variable,so we can use outerThis in function two.

Related

this.method return undefined

function Z(params) {
for (var j in params) {
this[j] = params[j];
}
}
Z.prototype = {
show: function () {
var _this = this;
$(window).bind('resize', this.adjust); // Return undefined? Why?
//$(window).bind('resize',function(){
// _this.adjust(); // This works.
//});
},
adjust: function () {
alert(this.id);
}
}
var a = new Z({
id: 5
});
a.show();
Hello, why this.adjust return undefined? But its working when anonymous function is being used.
In Javascript closures, the this keyword is late binding. Which means it is not evaluated until the function is actually called.
So when the "resize" event is fired your context is already gone.
Assigning the value to a variable then using that variable inside a function creates a closure. As long as that function is referenced somewhere it will retain the value of _this.
_this in your example uses early binding while this uses late binding. At the time that your resize event handler is called the value of this will be the window object which obviously doesn't have a method adjust
See also: http://javascript.info/tutorial/binding
It is because this in alert(this.id); is refering to the window object now and not to your a instance.
This a "this" scope issue. Try replacing the statement:
$(window).bind('resize', this.adjust);
by this:
$(window).bind('resize', _this.adjust);

What is a best practice for ensuring "this" context in Javascript?

Here's a sample of a simple Javascript class with a public and private method (fiddle: http://jsfiddle.net/gY4mh/).
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
Calling the private function from the public one results in "this" being the window object. How should I ensure my private methods are called with the class context and not window? Would this be undesirable?
Using closure. Basically any variable declared in function, remains available to functions inside that function :
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Another approach is to use "apply" to explicitly set what the methods "this" should be bound to.
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
Yet another approach is to use "call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
both "apply" and "call" take the object that you want to bind "this" to as the first argument and an array of arguments to pass in to the method you are calling as the second arg.
It is worth understanding how the value of this in javascript is determined in addition to just having someone tell you a code fix. In javascript, this is determined the following ways:
If you call a function via an object property as in object.method(), then this will be set to the object inside the method.
If you call a function directly without any object reference such as function(), then this will be set to either the global object (window in a browser) or in strict mode, it will be set to undefined.
If you create a new object with the new operator, then the constructor function for that object will be called with the value of this set to the newly created object instance. You can think of this as the same as item 1 above, the object is created and then the constructor method on it is called.
If you call a function with .call() or .apply() as in function.call(xxx), then you can determine exactly what this is set to by what argument you pass to .call() or .apply(). You can read more about .call() here and .apply() here on MDN.
If you use function.bind(xxx) this creates a small stub function that makes sure your function is called with the desired value of this. Internally, this likely just uses .apply(), but it's a shortcut for when you want a single callback function that will have the right value of this when it's called (when you aren't the direct caller of the function).
In a callback function, the caller of the callback function is responsible for determining the desired value of this. For example, in an event handler callback function, the browser generally sets this to be the DOM object that is handling the event.
There's a nice summary of these various methods here on MDN.
So, in your case, you are making a normal function call when you call privateFunction(). So, as expected the value of this is set as in option 2 above.
If you want to explictly set it to the current value of this in your method, then you can do so like this:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Other methods such as using a closure and defined var that = this are best used for the case of callback functions when you are not the caller of the function and thus can't use 1-4. There is no reason to do it that way in your particular case. I would say that using .call() is a better practice. Then, your function can actually use this and can behave like a private method which appears to be the behavior you seek.
I guess most used way to get this done is by simply caching (storing) the value of this in a local context variable
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
a more convenient way is to invoke Function.prototype.bind to bind a context to a function (forever). However, the only restriction here is that this requires a ES5-ready browser and bound functions are slightly slower.
var privateFunction = function() {
console.log(this);
}.bind(this);
I would say the proper way is to use prototyping since it was after all how Javascript was designed. So:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
Here's a fiddle http://jsfiddle.net/BFm2V/
If you're not using EcmaScript5, I'd recommend using Underscore's (or LoDash's) bind function.
In addition to the other answers given here, if you don't have an ES5-ready browser, you can create your own "permanently-bound function" quite simply with code like so:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
Then use it like this:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
Voilà -- this is magically the outer context's this instead of the inner one!
You can even get ES5-like functionality if it's missing in your browser like so (this does nothing if you already have it):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
Then use var yourFunction = function() {}.bind(thisobj); exactly the same way.
ES5-like code that is fully compliant (as possible), checking parameter types and so on, can be found at mozilla Function.prototype.bind. There are some differences that could trip you up if you're doing a few different advanced things with functions, so read up on it at the link if you want to go that route.
I would say assigning self to this is a common technique:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
Using apply (as others have suggested) also works, though it's a bit more complex in my opinion.
It might be beyond the scope of this question, but I would also recommend considering a different approach to JavaScript where you actually don't use the this keyword at all. A former colleague of mine at ThoughtWorks, Pete Hodgson, wrote a really helpful article, Class-less JavaScript, explaining one way to do this.

JS: Scope Inside Constructor Function

I am new to OOP and I am trying to rewrite a simple JS function as an object literal and then as a constructor function. I succeeded in writing the object literal version, but I clearly have a scope problem inside the anon function which handles the onclick event (inside my constructor function). Please let me know how to make the onclick event work.
Object Literal Version Which WORKS:
var submit = {
form_id : "",
submit_button_id : "",
submit_form: function(){
var button = document.getElementById(submit.submit_button_id);
var form = document.getElementById(submit.form_id);
button.onclick = function(){
form.submit();
return false;
}
}
}
addLoadEvent(function(){
submit.form_id = "form_vars";
submit.submit_button_id = "but_submit";
submit.submit_form();
});
Constructor Function Version Which DOESN'T WORK:
function SubmitForm(button_id, form_id){
this.submit_button = document.getElementById(button_id);
this.form = document.getElementById(form_id);
this.submit_form = function(){
// problem function below
this.submit_button.onclick = function(){
this.form.submit();
}
}
}
addLoadEvent(function(){
var form_to_submit = new SubmitForm("but_submit", "form_vars");
form_to_submit.submit_form();
});
P.S. I am aware that I should be using DOM API event handlers instead of HTML-DOM ones. I am just tackling one thing at a time.
this inside your function will not necessarily be the same as this in the constructor, it is decided by how you call that function. For instance, if you call a function f by doing f(), then this === window, if it is a method on an object x.f() then this === x. Also see Function:call and Function:apply.
Simplest way to solve this is to have a local variable in the constructor (like var me = this;) and then use me instead of this in the inner function, since that will not be overridden.
Read up on lexical scoping and closures if you want to learn more.

Accessing this from within an object's inline function

I'm having difficulty referencing "this" from within a javascript inline function, within an object method.
var testObject = {
oThis : this,
testVariable : "somestring",
init : function(){
console.log(this.testVariable); // outputs testVariable as expected
this.testObject.submit(function(){
var anotherThis = this;
console.log(this.testVariable) // undefined
console.log(oThis.testVariable) // undefined
console.log(testObject.testVariable) // outputs testVariable
console.log(anotherThis.testVariable) // undefined
}
}
How do I access this.testVariable from within the submit function?
I'm also using jQuery as well, if that makes a difference.
I wonder if this is the best approach - and maybe I should have submit as a separate function, and then reference that inline, like:
init : function(){
this.testObject.submit = this.submitForm;
},
submitForm : function(){
// do validation here
console.log(this.testVariable) // outputs testvariable
.
.
.
return valid;
}
But this didn't seem to work either - and I think I'd just like to keep the submit function inline within my init method for now.
A common way is to assign the this you want to a local variable.
init: function() {
var _this = this;
this.testObject.submit(function() {
console.log(_this.testVariable); // outputs testVariable
});
}
You could also do this using ES6 arrow functions:
init: function(){
this.testObject.submit( () => {
console.log(this.testVariable);
}
}
Arrow functions capture the this value of the enclosing context, avoiding the need to assign this to a new variable, or to use bound functions.
The "this" variable is bound dynamically when a function — any function, regardless of where it was defined — is called.
Without seeing what that "submit" function is supposed to do, or where it's supposed to be used, it's hard to say how to change it. One thing you could do is to define "submit" in your "init" function:
init: function() {
// whatever
var instance = this;
instance.submitForm = function() {
console.log(instance.testVariable);
// ...
};
}
As long as "init" is called initially with "this" set to an instance of one of your objects, you should be good.
You can only access the oThis variable from the context of the object, which is lost because you are inside of another function. or through instantiating a new object. like this
var testInstance = new testObject();
Then you could access oThis by using:
testInstance.oThis;
but that would be redundant
I would try something like this Matt:
init: function(){
var self = this; // this allows you to access the parent object from different contexts
this.testObject.submit(function(){
console.log(self.testVariable);
}
A possible answer is to use arrow functions and pass in the object that "this" should refer to...
function create() {
var thing = { name: "thingy" };
thing.doStuff = function() {
alert(this.name);
}
thing.doStuff(thing);
}
The reason this works is arrow functions automatically have a final thisArg optional parameter which is bound to this.

Confusion with "this" object in JavaScript anonymous functions

Hi I have following JavaScript code that I am trying to run. My aim is to grasp the meaning of this in different scopes and different types of invocations in JavaScript.
If you look in code below: I have a inner anonymous function, which is getting assigned to innerStuff variable. In that anonymous function as such this points to window object and not the outer function object or anything else. Event though it still has access to out function's variables.
Anyway, I am not sure, why that would be; but if you look at code below, I pass this in form of that to innerStuff later and it works just fine and prints object with doofus attribute in console.
var someStuff = {
doofus:"whatever",
newF: function()
{
var that = this;
console.log(that);
var innerStuff = function(topThis){
console.log(topThis);
};
return innerStuff(that);
}
}
someStuff.newF();
Now I am changing a code only little bit. And instead of assigning it to innerStuff, I'll just directly return the function by invoking it as shown below:
var someStuff = {
doofus:"whatever",
newF: function()
{
var that = this;
console.log(that);
return function(that){
console.log(that);
}();
}
}
someStuff.newF();
This prints undefined for the inner anonymous function. Is it because there is a clash between a that that is being passed as parameter and a that defined in outside function?
I thought the parameter would have overriden the visibility. Why would the value be not retained?
This is utterly confusing.
On the other hand if I don't pass that, but instead just use it, because visibility is there, the outcome is proper and as expected.
What is it that I am missing? Is it the clash between the variables, present in same scope?
Is there a good reason, that inner functions have this bound to window object?
this in JavaScript refers to the object that you called a method on. If you invoke a function as someObject.functionName(args), then this will be bound to that object. If you simply invoke a bare function, as in functionName(args), then this will be bound to the window object.
Inside of newF in the second example, you are shadowing the that variable in your inner function, but not passing anything into it, so it is undefined.
var that = this;
console.log(that);
return function(that){
console.log(that);
}();
You probably want the following instead, if you want something that is equivalent to your first example (passing that in to the inner function):
var that = this;
console.log(that);
return function(that){
console.log(that);
}(that);
Or the following, if you don't want to shadow it and just use the outer function's binding:
var that = this;
console.log(that);
return function(){
console.log(that);
}();
In your second example, when you invoke the anonymous function, the parameter that is not defined (you aren't passing anything to it.) You can do this:
newF: function()
{
var that = this;
console.log(that);
return function(that){
console.log(that);
}(that); // note that we are passing our 'that' in as 'that'
}
That will keep the proper value of the variable around.
However, since you are scoping var that above, you could just remove the function parameter as well:
newF: function()
{
var that = this;
console.log(that);
return function(){
console.log(that);
}(); // 'that' is referenced above.
}
As far as why anonymous functions have window as their this: whenever you call a function without a context (i.e. somef() vs context.somef()) this will point to the window object.
You can override that and pass a this using .apply(context, argumentsArray) or .call(context, arg1, arg2, arg3) on a function. An example:
newF: function()
{
console.log('Outer:', this);
var innerF = function(){
console.log('Inner:', this);
};
return innerF.apply(this,arguments);
}
In your first code example, the anonymous function, though declared within a function that is a member of the someStuff object, is not a member of the someStuff object. For that reason, this in that function is a reference to the window object. If you wanted to invoke the anonymous function and have control over the this reference, you could do the following:
var someStuff = {
doofus:"whatever",
newF: function()
{
var that = this;
console.log(that);
var innerStuff = function(){
console.log(this);
};
return innerStuff.apply(this);
}
}
someStuff.newF();
In your second example, your actually creating an anonymous function, executing it, and then returning the value that the anonymous function returned. However, your anonymous function did not return anything. Additionally, you have a variable name conflict. You could do:
var someStuff = {
doofus:"whatever",
newF: function()
{
var that = this;
console.log(that);
return function(){
console.log(that);
return true;
}();
}
}
someStuff.newF();
I added the return true because your function should return something, since the function that is executing it is returning the return value of the anonymous function. Whether it returns true or false or a string or an object or whatever else depends on the scenario.

Categories

Resources