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

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

Related

Equivalent of interfaces in 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?

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

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 can i inherit from 2 objects and use both the objects as a prototype of another

I am learning js inheritance and prototyping and my naming is probably totally off i am sorry for that.
i am trying to create a super object and prototype 2 sub object as properties and then inside one of the sub object call a function that is found in the other. it doesn't work for some reason.
UPDATE
my goal in here is:
I am trying to make a small game - for fun and practice.
My plan was to have 1 basic object called(object) that has positioning and other properties (that every other object will have) another object called(controls) for controls. Only objects that can move will have that object as well.
players are also objects and they will have both "object" and "controls". as their prototype.
Hope that cleared things a bit.
Code:
// sub Object1
function object(){
this.speed = 1;
this.walkDistant = 5;
}
// sub Object2
function controls(){
this.moveLeft = function(){
console.log(this.speed , this.walkDistant);
return this.speed * this.walkDistant;
}
}
// super Object
function player(){
// DoesNothing
}
player.prototype.object = new object();
player.prototype.controls = new controls();
var firstPlayer = new player();
console.log(firstPlayer.controls.moveLeft());
Or if you prefer fiddle : http://jsfiddle.net/rMaKa/1/
Because a Player can be controlled you can mix in Controls with Player. Your object constructor function is a badly chosen name because a constructor function should start with a capital making it Object and you'd overwrite window.Object (bad idea). For this reason I've renamed it to Base. Player is a Base object and can be controlled so inherits from Base and has Controls mixed in.
For more information about constructor functions, mix ins, instance members and prototype check this link.
function Base() {
this.speed = 1;
this.walkDistant = 5;
}
// sub Object2
function Controls() {
}
Controls.prototype.moveLeft = function() {
console.log(this.speed, this.walkDistant);
return this.speed * this.walkDistant;
}
// super Object
function Player() {
//make player have Base instance members
Base.call(this);
//make player heve Controls instance members
Controls.call(this);
}
//player is a base object
Player.prototype = Object.create(Base.prototype);
//repair constrictor
Player.prototype.constructor = Player;
//Player can be controlled, copy controls prototype on player (mixin)
// this would be better suited in a helper function, see link posted in answer
var stuff;
for (stuff in Controls.prototype) {
if (Controls.prototype.hasOwnProperty(stuff)) {
Player.prototype[stuff] = Controls.prototype[stuff];
}
}
var firstPlayer = new Player();
console.log(firstPlayer.moveLeft());
If you want the player to have controls you can try something like this:
function Controls(what) {
//what do we need to control
this.controlWhat=what;
}
Controls.prototype.moveLeft = function() {
console.log(this.controlWhat.speed, this.controlWhat.walkDistant);
return this.controlWhat.speed * this.controlWhat.walkDistant;
};
function Player() {
this.speed = 1;
this.walkDistant = 5;
this.controls=new Controls(this);
}
var firstPlayer = new Player();
console.log(firstPlayer.controls.moveLeft());
The problem is that you are trying to access a property that pertences to subObj1 from subObj2, but is the superObj that inherit both.
To achieve that, you should make your subObj1 inherit the subObj2.
// sub Object1
function name(){
this.name = function(){
var myName = 'FirstName';
console.log(myName, this.last.lastName);
}
this.callName = function(){
this.name();
};
}
// sub Object2
function lastName(){
this.lastName ='someLastName';
}
// super Object
function fullName(){
// DoesNothing
}
name.prototype.last = new lastName();
fullName.prototype.name = new name();
var myName = new fullName();
myName.name.callName();
You can see this fiddle
You can use Mixins to extend the functionality of an object using functionality already implemented in other objects. You could also have it that the sub-objects know about the super object as below.
function subClassA(containerClass) {
this.containerClass = containerClass;
this.methodA = function() {
console.log(this.containerClass.b.methodB());
}
}
function subClassB(containerClass) {
this.containerClass = containerClass;
this.methodB = function() {
return 12345;
}
}
function containerClass() {
this.a = new subClassA(this);
this.b = new subClassB(this);
}
var cc = new containerClass();
cc.a.methodA();
The Mixin approach would look something like this:
// extend function to add mixin support
function extend(destination, source) {
for (var k in source)
if (source.hasOwnProperty(k))
destination[k] = source[k];
return destination;
}
function subClassA() { }
subClassA.prototype.methodA = function() {
console.log(this.methodB());
};
function subClassB() { }
subClassB.prototype.methodB = function() {
return 12345;
};
function superClass() {
// ----------------
}
// add the subClassA and subClassB functionality
extend(superClass.prototype, subClassA.prototype);
extend(superClass.prototype, subClassB.prototype);
var sc = new superClass();
sc.methodA();

Module/prototype and multiple instances

I'm trying to get a grip on "OOP" JavaScript techniques, and I began writing a small test application today. Basically, it's a game loop and on each update coordinates are to be increased so that an HTML element moves.
The problem is I want to be able to run more than one instance of the app, and therefore I'm trying to store the instance data in this, but what is saved in my constructor and exec() method is not available in the private update() method. What seems to be the officer, problem?
var Jsloth = (function () {
var Jsloth = function () {
var sloth = document.createElement('div');
var attr = document.createAttribute('class');
attr.value = 'sloth';
sloth.setAttributeNode(attr);
this.sloth = document.getElementsByTagName('body')[0].appendChild(sloth);
};
var exec = function () {
this.x = 0;
this.y = 0;
var that = this;
setInterval(function () {
that.update();
}, 1000/10);
};
var update = function () {
this.x++;
this.y++;
this.sloth.style.left = this.x + 'px';
this.sloth.style.bottom = this.y + 'px';
};
Jsloth.prototype.constructor = Jsloth;
Jsloth.prototype.exec = exec;
Jsloth.prototype.update = update;
return Jsloth;
})();
var sloth1 = new Jsloth();
sloth1.exec();
Edit: Updated code with a working solution!
In JavaScript, this is (almost) entirely decided by how you call a function, not where/how it's defined.
The way you're calling update:
update();
...this will be the global object (window on browsers), or undefined if you use "use strict".
To set this within update, use call or apply:
update.call(this);
// or
update.apply(this);
More (on my blog):
Mythical methods
You must remember this
You've not added update to the prototype. The value of this in that method will be most likely the window object.
Change your call from this:
update();
To this:
update.call(this);
Or add update to the .prototype:
Jsloth.prototype.update = update;
and use:
this.update();
But if you're going to call update() from the setInterval(), you'll need to ensure the proper this value.
To do that, you can pass an anonymous function, and keep a reference to the outer this value in a variable.
var exec = function () {
this.x = 0;
this.y = 0;
var that = this;
setInterval(function() {
that.update();
//update.call(that); // if you didn't add update() to the .prototype
}, 1000/10);
};

Categories

Resources