Equivalent of interfaces in javascript - javascript

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?

Related

How do I wrap a javascript function with dynamic arguments?

I'd like to wrap some dynamically created javascript functions, similar to Daniel's accepted answer here:
How do I store javascript functions in a queue for them to be executed eventually
// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
return function() {
fn.apply(context, params);
};
}
The difference is I'd like the argument values to be dynamic at time of execution - is it possible to pass a reference to a variable in the arguments, which could be updated after it is wrapped?
Here's what I'd like to do:
// I have a function to be wrapped
var sayStuff = function(a,b) {
console.log(a);
console.log(b);
}
// Variables I'd like to pass
var randomNumberA = 0;
var randomNumberB = 0;
// Wrap the function
var fun = wrapFunction(sayStuff, this, [*reference randomNumberA*,*reference randomNumberB*]);
// variables get changed
randomNumberA = Math.random()*100;
randomNumberB = Math.random()*100;
// Execute the function using current values of randomNumberA & randomNumberB
fun();
If possible I'd like to do this without changing sayStuff, I have a lot of existing functions like this I'm hoping to wrap, which also get used outside of the wrapping, so ideally I'd like to not replace the arguments with an object.
Hope that makes sense, Thanks!
If the function and the variable will be created in the same scope you can just use that:
var randomNumber = 0;
var fun = function(){ alert(randomNumber); }
randomNumber = 10;
// Now this will alert 10, because when fun is executed
// JS looks in his scope to find what randomNumber is.
fun();
This happens because functions in javascript works as Closures, they carry their environment with them. See: https://en.wikipedia.org/wiki/Closure_(computer_programming)
So if randomNumber will be changed out of the scope where you bind that function, you need to use an object, this is because in javascript we don't have "pointers" or references to pass by. One way is using a object.
function giveMeAFunction(){
var params = { randomNumber: 0 }
var fun = function(){ alert(scope.randomNumber); }
return {fun: fun, scope: scope};
}
var paramsAndFun = giveMeAFunction()
// Now you can change the variables in the scope and call the function
paramsAndFun.params.randomNumber = 10;
paramsAndFun.fun(); // Will alert 10
// Now if you replace the entire params object it will not work
// This is because you will replacing it with a new object while
// The one that is referenced in the scope where fun was created is
// the old one.
paramsAndFun.params = { randomNumber: 15 };
paramsAndFun.fun(); // will still alert 10
Now let's get to binding part of the problem.
There is already Function.prototype.bind function to help you with that.
For example:
var sayStuff = function(opts) {
alert(otions.randomNumber);
}
var options = { randomNumber: 0 };
var fun = sayStuff.bind(this, options);
options.randomNumber = 10;
fun(); // Will print 10
There is a lot going on here. Sorry if I made everything confuse.
If the dynamic arguments are defined in the context argument, a solution can be based passing the name of the variables and then, at execution time, calculate its current value:
var wrapFunction = function(fn, context) {
var xArg = arguments;
return function() {
var argsArray = [];
for (var i = 2; i < xArg.length; i++) {
argsArray.push(context[xArg[i]]);
}
fn.apply(context, argsArray);
};
}
var sayStuff = function() {
for (var i = 0; i < arguments.length; i++) {
console.log('sayStuff func: ' + arguments[i]);
}
}
var randomNumber1 = 0;
var randomNumber2 = 0;
var fun = wrapFunction(sayStuff, this, 'randomNumber1', 'randomNumber2');
randomNumber1 = Math.random()*100;
randomNumber2 = Math.random()*100;
console.log('randomNumber1: ' + randomNumber1);
console.log('randomNumber2: ' + randomNumber2);
fun();

Scope of variables in module pattern

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".

How does one manipulate a variable in a prototype?

I'm new to Javascript and was wondering how a public variable in a prototype can be modified.
function Thing (val)
{
this.x = val;
this.addToX = function (valIn)
{
this.x += valIn;
};
}
function ChildThing ()
{
this.y = 55;
}
ChildThing.prototype = new Thing(10);
var frank = new ChildThing();
console.log("out1: " + frank.x);
frank.addToX(10);
console.log("out2: " + frank.x);
This code takes the value in the prototype x which is 10 and adds 10 to it in the addToX function. The new x value is stored in the top level object rather than replacing the current x value in the prototype.
Is there a way to overwrite the existing x in the prototype or am I using Javascript wrong?
That depends. What would be the point of altering x on the prototype? Generally you don't want to chang shared properties. But I imagine that there could be a use case (generating new id?).
As for the question: you can simply do:
this.addToX = function(valIn) {
ChildThing.prototype.x += valIn;
};
Again I do not advice doing it.
EDIT You can make it without referencing the child by defining the prototype before setting it as a prototype, i.e.
var my_proto = new Thing(10);
ChildThing.prototype = my_proto;
and then
this.addToX = function(valIn) {
my_proto.x += valIn;
};
Or you can even play with the singleton pattern.
What you seem to be wanting is very similar to what static members are in classical languages. It's very misleading to call a method on an object instance and have that method modify the state of other objects outside of it's scope. Therefore, I believe you shounldn't be relying on prototypes at all for this behavior. Here's what you could do to mimic static members.
function SomeClass() {}
SomeClass.staticMember = 'initial value';
SomeClass.changeStaticMember = function (val) { this.staticMember = val; };
SomeClass.changeStaticMember('another value');
I believe the code above is less cryptic and better at communicating the behavior. However if you still want to share mutable values across instances through the prototype you could simply avoid writing the property directly as a primitive value, but rather wrap it within a mutable shared object like below. Note that the whole inheritance hierarchy will share the same x value.
//Mutable class to encapsulate the value of X
function XValue(val) {
this.value = val;
}
XValue.prototype = {
constructor: XValue,
valueOf: function () { return this.value; },
set: function (val) { this.value = val; },
add: function (val) { this.value += val; }
};
function Thing(x) {
this.x = x;
}
Thing.prototype = {
constructor: Thing,
_x: new XValue(), //shared mutable object representing the value of X
get x() { return this._x.valueOf(); },
set x(val) { this._x.set(val); },
addToX: function (val) { this._x.add(val); }
};
function ChildThing() {
Thing.call(this, 10); //call parent constructor
}
ChildThing.prototype = Object.create(Thing.prototype);
//helper for snippet
function log(text) {
var span = document.createElement('span');
span.innerHTML = text;
document.body.appendChild(span);
document.body.appendChild(document.createElement('br'));
}
var ct = new ChildThing();
ct.addToX(10);
log('ct.x → ' + ct.x);
log('Thing.prototype.x → ' + Thing.prototype.x);

How to access parent of an object in an object [duplicate]

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);
}
}

javascript classes - is "this.varname" required for each use?

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.

Categories

Resources