I have a javascript class like this:
function Foo() {
this.x = 5;
this.y = x + 10;
}
Does 'x' not get scoped to the instance of the class when I don't use '.this'? If so, how do we use callbacks then? I have something like:
function Foo() {
this.x = 5;
this.grok = function() {
jQuery(blah).animate({
..,
function(){
x = 55;
}
});
}
}
so jquery gives a chance for a callback, but how do I access the 'x' member variable of the parent class in that context then?
Thanks
In your specific case, you have to store a reference to this in another variable:
function Foo() {
this.x = 5;
this.grok = function() {
var that = this;
jQuery(blah).animate({
..,
function(){
that.x = 55;
}
});
}
}
The anonymous function has access to all variables defined in grok. If you just use x, it would be a global variable.
What you can do is to use another variable as a pointer to the correct this then use a closure to capture that variable:
function Foo() {
this.x = 5;
var foo_this = this;
this.grok = function() {
jQuery(blah).animate({
..,
function(){
foo_this.x = 55;
}
});
}
}
Some people like to use the variable name that whenever they point to this. I personally prefer to use self.
Related
var ModuelPattern=(function () {
var x="A"
var change=function(){
if(x==="A"){
x="B"
}
else{
x="A"
}
}
return{
x:x,
f:change
}
})();
ModuelPattern.f()
console.log(ModuelPattern.x)
I cannot figure out an way to update x inside IIFE using revealing-module pattern and access outside the
Scope
You can make x a getter function in the returned object:
var ModuelPattern=(function () {
var x="A"
var change=function(){
if(x==="A"){
x="B"
}
else{
x="A"
}
}
return{
get x() { return x; },
set x(_) {},
f:change
}
})();
ModuelPattern.f()
console.log(ModuelPattern.x)
That allows the returned object to access the local variable in the closure formed from calling the original factory function. I added a dummy setter function as an illustration.
Use this keyword to access object's own properties.
var ModuelPattern=(function () {
this.x = "A"
this.change=function() {
if(this.x==="A"){
this.x = "B"
}
else{
this.x = "A"
}
}
return {
x: this.x,
f: this.change
}
})();
console.log(ModuelPattern.x)
ModuelPattern.f()
console.log(ModuelPattern.x)
I have a function object in javascript called BlinkyTextBox Inside of that I have 2 Shape objects that act as scroll buttons. I need a something very simple to happen which is just increment or decrement a variable called scrollY.
I tried it with an anonymous inner function, but the function couldn't recognize the member variables. Now I tried it with a member function, but it doesn't work with that either...
Here are both samples of what I am talking about.
function BlinkyTextBox(textdata, font, w, h)
{
this.scrollY = -50;
this.scrollBarYTop = new Button();
this.scrollBarYTop.callFunction = this.scrollUp;
this.scrollBarYBottom = new Button();
this.scrollBarYBottom.callFunction = function()
{
this.scrollY -= 10;
}
}
BlinkyTextBox.prototype.scrollUp = function()
{
this.scrollY += 10;
}
The problem here is that once you assign a function to another object the this inside that function will refer to the new object instead of the object the function came from.
For example:
var a = {
message : 'Hello!',
say : function () { return this.message }
}
var b = {
message : 'Goodbye'
}
b.say = a.say;
console.log(a.say()); // Hello!
console.log(b.say()); // Goodbye
Notice that we didn't do anything to the function say(). We just assigned it to b and it now print's the message from b instead of a.
Now, let's look at your code:
this.scrollBarYBottom.callFunction = function()
{
this.scrollY -= 10; // refers to scrollBarYBottom.scrollY
// not BlinkyTextBox.scrollY
}
Same thing happens to the other method:
this.scrollBarYTop.callFunction = this.scrollUp;
// the this inside scrollUp will now refer to scrollBarYTop
Traditionally, to fix this you'd use an alias for this:
var myself = this;
this.scrollBarYBottom.callFunction = function()
{
myself.scrollY -= 10;
}
But with ES5 you can use the .bind() method:
this.scrollBarYBottom.callFunction = (function()
{
this.scrollY -= 10;
}).bind(this);
and:
this.scrollBarYTop.callFunction = this.scrollUp.bind(this);
Refer to this answer for a more detailed explanation of this: How does the "this" keyword in Javascript act within an object literal?
I am trying to understand how I can touch/change/increment my privately scoped variable x in the following script. I'm using the Module pattern here, and thought I could reach into and set the private variables from a public return module declared property or method, but nothing I'm trying is working. Related: when do you declare a new instance of func vs. accessing func as a static delcared variable?
var func = (function() {
var x = 1;
var squareX = function() {
return x * x;
};
var addOne = function() {
x++;
}
return {
X: x,
Xq: squareX,
AddOne: addOne
};
});
func().X = 9; // expecting privately scoped x = 9
func().AddOne(); // expecting privately scoped x = 10
document.write(func().Xq()); // expecting 100 actual = 1
The point of the module pattern is to create a persistent, private scope which is invisible from the outside. Unfortunately, every time you call func, you're creating a new scope (with new return functions and their closures), so all of your operations are discarded afterwards.
Instead of calling func multiple times, just do it once to setup the "module" (you can even do this immediately, with an IIFE), and then perform operations on the result.
var func = function() {
var x = 1; // this is the private variable
var squareX = function() {
return x * x;
};
var addOne = function() {
x++;
};
return {
// Note, you can't just do "X: x,"
// since that will just create a copy;
// you have to use properties
get X() { return x; },
set X(val) { x = val; },
Xq: squareX,
AddOne: addOne
};
};
var funcModule = func();
funcModule.X = 9;
funcModule.AddOne();
document.write(funcModule.Xq());
Note that the reason you need an explicit getter and setter for the X module property is because you need to be able to modify the inner (hidden) variable x. Properties are available in all modern browsers, including IE9+. If you're working in IE8 or below, you'll need to define explicit getX and setX methods, and call them directly (you won't just be able to do funcModule.X = 5).
You need a setter, and you need an IIFE:
var func = (function() {
var x = 1;
var squareX = function() {
return x * x;
};
var addOne = function() {
x++;
}
return {
X: function(value) {
if (value !== undefined) {
x = value;
}
return x; // we can use this as a getter too!
},
Xq: squareX,
AddOne: addOne
};
})(); // <-- this actually runs the function - this makes it an IIFE
document.write("X is " + func.X() + "</br>");
func.X(9); // expecting privately scoped x = 9
document.write("now X is " + func.X() + "</br>");
func.AddOne(); // expecting privately scoped x = 10
document.write("now X is " + func.X() + "</br>");
document.write(func.Xq()); // expecting 100 actual = 100
You're using the Revealing Module Pattern to hide your private instance variable. When using that pattern, you must use a setter of some kind to change your private instance variable. Here is another StackOverflow post where someone else was having the same problem.
I don't recommend that you use the Revealing Module Pattern. In fact, I just gave a talk at NationJS 2014 titled "The Revealing Module is an Anti-Pattern".
I have a class method and a closure within this method. How I can access to class member from closure?
Person = function(x) {
this.x = x;
}
Person.prototype = {
myMethod: function() {
$('#myBtn').click( function() {
// how to access to this.x? the this reference points in another context
});
}
}
Use of Function.prototype.bind will help you here
Person = function(x) {
this.x = x;
}
Person.prototype.myMethod = function() {
$('#myBtn').click(function() {
this.x;
}.bind(this));
};
You can use some better separation of code here too
Person = function(x) {
this.x = x;
};
Person.prototype.myMethod = function {
$('#myBtn').click(this.clickHandler.bind(this));
};
Person.prototype.clickHandler = function(event) {
console.log(this.x);
};
Note if you want to support older browsers, check out es5-shim
EDIT
I'm revisiting this after ~6 months and I would probably write the above code differently. I like the private/public exposure here. Also, no need for any fanciful binds or anything like that ^.^
function Person(x, $button) {
// private api
function onClick(event) {
console.log(x);
}
function myMethod() {
$button.click();
}
// exports
this.x = x;
this.myMethod = myMethod;
// init
$button.click(onClick);
}
var b = $("#myBtn"),
p = new Person("foo", b);
p.x; // "foo"
p.myMethod(); // "foo"
btn.click(); // "foo"
Just assign this to some other variable, for example _this:
Person = function(x) {
this.x = x;
}
Person.prototype = {
myMethod: function() {
var _this = this;
$('#myBtn').click( function() {
console.log(_this.x);
});
}
}
Person = function(x) {
this.x = x;
}
Person.prototype = {
myMethod: function() {
var self = this;
$('#myBtn').click( function() {
// Access to self.x
});
}
}
A proxy would be very useful here.
Right now, you're assigning an anonymous function to the click event. By default the context will be the event's and separate from your object.
With a proxy you can assign a particular context to a (callback) function. Thus, when the event fires, you're dealing with your person object.
Assign the event handler in a separate function like initialize(), and have myMethod() be the handler.
Use a JQuery.proxy() to assign the object`s context to the event handler.
Person.prototype = {
initialize: function() {
$('#myBtn').click($.proxy(this.myMethod, this));
},
myMethod: function(event) {
...
console.log(this); // Person object
}
}
Just to elicit the difference between my and #naomik's solution:
JQuery.proxy() is a temporary or narrow assignment to a context.
Function.prototype.bind() is a strong context assignment. The method will be "forever" bound to the context you give it.
This question already has answers here:
javascript get parent nested object?
(7 answers)
Closed 9 years ago.
Hi guys let's say I have this:
function example()
{
this.x = 0;
this.y = 32;
this.example2 = function()
{
}
}
How would I be able to access example.x/example.y from within example2?
I'm asking because I'm creating my first 'real' html5 game and I'm planning on having 1 big Game object and 'Models' within that object (Player, Enemies, etc). Unless there's a better way to do it...I have done working prototypes but they were all in one files and not really structured.
If you object only plans to have 1 parent, you can do it this way:
function example() {
this.x = 0;
this.y = 32;
this.example2 = new function() {
this.parent = undefined;
}
this.example2.parent = this;
}
var firstobject = new example();
// Saving a reference to example2.
var example2Object = firstobject.example2;
// Because of parent variable, you can access example2 parent without needing to have the parent object in a variable.
console.log(example2Object.parent.x);
console.log(example2Object.parent.y);
There are tons of ways of setting parent, this is just an example.
Like this:
function example()
{
this.x = 0;
this.y = 32;
this.example2 = function()
{
console.log(this.x); // 0
}
}
If you want your methods to still reference their original object when used in isolation you need a closure:
function example()
{
this.x = 0;
this.y = 32;
this.example2 = proxy(this, function() {
console.log(this.x);
});
}
var x = new example(),
fn = x.example2; // isolate method
fn(); // this will still work
It's using this helper function to bind the function to an object:
// helper function to bind fn to ctx (context)
function proxy(ctx, fn)
{
return function() {
return fn.apply(ctx, arguments);
}
}