JavaScript - object's functions referencing its fields - javascript

Here is a (very) simplified version of my code:
function Ctor() {
this.i = 0;
this.increment = function() { this.i++; },
this.decrement = function() { this.i--; },
this.display = function() { alert(this.i); }
};
The problem is, when the code is run, under some circumstances this now points to something else. I do more or less understand that this changes context from one function to another, but I though my increment function (and the others) would, by the magic of closures, "remember" what this is supposed to be.
I tried just eliminating this altogether, and simply referencing i in the functions. That failed also.
What should these functions look like?

You can not rely on what's in this in JavaScript. More on this topic.
I see you probably want to introduce private attributes like in OOP languages. John Resig described this issue very well.
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
// => "test2"
JavaScript works a lot differently than conventional languages like Java, C++ or PHP. But you can get used to it :)

In the instances where this changes, you can do this:
function() { obj.display(); }
Example:
var obj = new Ctor();
function foo(fn) {
fn();
}
foo(function() {
obj.display();
});
An alternative is to modify foo() to accept the context to execute the function with, like this:
function foo(fn, context) {
fn.call(context);
}

Related

Why we use public and private variable separately

var Command = function () {
var _self = this,
//flag to indicate that the operation is running
_isRunning = ko.observable(false),
//property to save the error message
_errorMessage = ko.observable();
//public properties
this.isRunning = _isRunning;
this.errorMessage = _errorMessage;
};
Why does this example use both private and public variables? Is this a design pattern we are following?
In just the code you've quoted, there's no reason. But my guess is that later in that outermost function, you have something like this:
this.doSomething = function() {
if (_isRunning()) {
// do one thing
} else {
// do something else
}
};
The reason for having the local variables is so that it doesn't matter what this value the function is called with.
That said, the _self variable already solves that problem for you just as well, making the _isRunning and _errorMessage variables purely convenience aliases. The above could just as well be:
this.doSomething = function() {
if (_self.isRunning()) {
// do one thing
} else {
// do something else
}
};
There's no particular design pattern here, it's just using the fact that functions created within other functions are closures over the local variables (and a few other things) of the function they're created in.

Limiting access to JavaScript variables

I'm modifying a module for a game that we are developing and it is built with ImpactJS game engine. What we wanted to do is to make the variables private or inaccessible to other classes.
For example:
this.object.variable = 100; // Not okay.
this.object.setVariable( 100 ); // Okay.
ig.module(
'game.data.server'
).requires(
).defines(function(){
ServerData = ig.class.Extend({
_variable : -1,
get variable() {
return this._variable ;
},
setVariable: function( value ) {
this._variable = value;
}
});
});
But JavaScript setter and getter return different outputs
We can't do several revisions because this is also accessed by other games that we are developing.
Is there a better solution?
First possibility
You could try doing this but as I haven't developed anything using ImpactJS it may not work as expected as it depends what the .class.extend() function does internally.
But it's worth a try.
var ServerData = ig.class.Extend((function() {
var privateVar = -1;
return {
getVariable: function() {
return privateVar;
},
setVariable: function(value) {
privateVar = value;
}
};
})());
This code may seem a bit confusing to you, but what I've changed I've created an immediately executing function to create a function closure, which is required to create private space in which I created private to closure variable that's not visible outside.
I would suggest you to read Douglas Crockford's Javascript and learn even more stuff about the language you're using.
Second possibility
According to link in comments it seems that we can use define's closure for private members as well:
var privateVar = -1;
var ServerData = ig.class.Extend({
getVariable: function() {
return privateVar;
},
setVariable: function(value) {
privateVar = value;
}
});

Crockford's Prototypical Inheritance - Usage

I've been building a small JS framework for use at my job, and I'd like to employ Douglas Crockford's prototypical inheritance patterns. I think I get the general idea of how the prototype object works, but what isn't clear is the way in which I would use this pattern beyond the simplest example.
I'll flesh it out to the point that I understand it.
(function () {
'use strict';
var Vehicles = {};
Vehicles.Vehicle = function () {
this.go = function () {
//go forwards
};
this.stop = function () {
//stop
};
};
Vehicles.Airplane = Object.create(Vehicles.Vehicle());
}());
So now my Vehicles.Airplane object can go() and stop(), but I want more. I want to add takeOff() and land() methods to this object. I could just use ugly dot notation afterwards:
Vehicles.Airplane.takeOff = function () {
//take off stuff
}
But that seems wrong, especially if I were to add many methods or properties. The question asked at here seems to be very similar to mine, but the answer doesn't quite ring true for me. The answer suggests that I should build an object literal before using Object.create, and that I should pass that object literal into the create method. In the example code given, however, it looks like their new object inherits nothing at all now.
What I'm hoping for is some syntax similar to:
Vehicles.Airplane = Object.create(Vehicles.Vehicle({
this.takeOff = function () {
//takeOff stuff
};
this.land = function () {
//land stuff
};
}));
I know this syntax will break terribly with Object.create right now, because of course I'm passing Vehicle.Vehicle a function rather than an object literal. That's beside the point. I'm wondering in what way I should build new properties into an object that inherits from another without having to list them out one at a time with dot notation after the fact.
EDIT:
Bergi, after some anguished thought on the topic, I think I really want to go with what you described as the "Classical Pattern". Here is my first stab at it (now with actual code snippets rather than mocked up hypotheticals - You even get to see my crappy method stubs):
CS.Button = function (o) {
o = o || {};
function init(self) {
self.domNode = dce('a');
self.text = o.text || '';
self.displayType = 'inline-block';
self.disabled = o.disabled || false;
self.domNode.appendChild(ctn(self.text));
if (o.handler) {
self.addListener('click', function () {
o.handler(self);
});
}
}
this.setText = function (newText) {
if (this.domNode.firstChild) {
this.domNode.removeChild(this.domNode.firstChild);
}
this.domNode.appendChild(ctn(newText));
};
init(this);
};
CS.Button.prototype = Object.create(CS.Displayable.prototype, {
constructor: {value: CS.Button, configurable: true}
});
CS.Displayable = function (o) { // o = CS Object
o = o || {};
var f = Object.create(new CS.Element(o));
function init(self) {
if (!self.domAnchor) {
self.domAnchor = self.domNode;
}
if (self.renderTo) {
self.renderTo.appendChild(self.domAnchor);
}
}
//Public Methods
this.addClass = function (newClass) {
if (typeof newClass === 'string') {
this.domNode.className += ' ' + newClass;
}
};
this.addListener = function (event, func, capture) {
if (this.domNode.addEventListener) {
this.domNode.addEventListener(event, func, capture);
} else if (this.domNode.attachEvent) {
this.domNode.attachEvent('on' + event, func);
}
};
this.blur = function () {
this.domNode.blur();
};
this.disable = function () {
this.disabled = true;
};
this.enable = function () {
this.disabled = false;
};
this.focus = function () {
this.domNode.focus();
};
this.getHeight = function () {
return this.domNode.offsetHeight;
};
this.getWidth = function () {
return this.domNode.offsetWidth;
};
this.hide = function () {
this.domNode.style.display = 'none';
};
this.isDisabled = function () {
return this.disabled;
};
this.removeClass = function (classToRemove) {
var classArray = this.domNode.className.split(' ');
classArray.splice(classArray.indexOf(classToRemove), 1);
this.domNode.className = classArray.join(' ');
};
this.removeListener = function () {
//Remove DOM element listener
};
this.show = function () {
this.domNode.style.display = this.displayType;
};
init(this);
};
CS.Displayable.prototype = Object.create(CS.Element.prototype, {
constructor: {value: CS.Displayable, configurable: true}
});
I should be quite clear and say that it's not quite working yet, but mostly I'd like your opinion on whether I'm even on the right track. You mentioned "instance-specific properties and methods" in a comment in your example. Does that mean that my this.setText method and others are wrongly placed, and won't be available to descendant items on the prototype chain?
Also, when used, it seems that the order of declaration now matters (I can't access CS.Displayable.prototype, because (I think) CS.Button is listed first, and CS.Displayable is undefined at the time that I'm trying to reference it). Is that something I'll just have to man up and deal with (put things in order of ancestry in the code rather than my OCD alphabetical order) or is there something I'm overlooking there as well?
Vehicles.Airplane = Object.create(Vehicles.Vehicle());
That line is wrong. You seem to want to use new Vehicles.Vehicle - never call a constructor without new!
Still, I'm not sure which pattern you want to use. Two are coming to my mind:
Classical Pattern
You are using constructor functions just as in standard JS. Inheritance is done by inheriting the prototype objects from each other, and applying the parent constructor on child instances. Your code should then look like this:
Vehicles.Vehicle = function () {
// instance-specific properties and methods,
// initialising
}
Vehicles.Vehicle.prototype.go = function () {
//go forwards
};
Vehicles.Vehicle.prototype.stop = function () {
//stop
};
Vehicles.Airplane = function() {
// Vehicles.Vehicle.apply(this, arguments);
// not needed here as "Vehicle" is empty
// maybe airplane-spefic instance initialisation
}
Vehicles.Airplane.prototype = Object.create(Vehicles.Vehicle.prototype, {
constructor: {value:Vehicles.Airplane, configurable:true}
}); // inheriting from Vehicle prototype, and overwriting constructor property
Vehicles.Airplane.prototype.takeOff = function () {
//take off stuff
};
// usage:
var airplane = new Vehicles.Airplace(params);
Pure Prototypical Pattern
You are using plain objects instead of constructor functions - no initialisation. To create instances, and to set up inheritance, only Object.create is used. It is like having only the prototype objects, and empty constructors. instancof does not work here. The code would look like this:
Vehicles.Vehicle = {
go: function () {
//go forwards
},
stop: function () {
//stop
}
}; // just an object literal
Vehicles.Airplane = Object.create(Vehicles.Vehicle); // a new object inheriting the go & stop methods
Vehicles.Airplane.takeOff = function () {
//take off stuff
};
// usage:
var airplane = Object.create(Vehicles.Airplane);
airplane.prop = params; // maybe also an "init" function, but that seems weird to me
You got Object.create wrong. The first argument should be an object (maybe that's why people suggested you pass a literal).
In your first example, you're actually passing undefined:
Vehicles.Airplane = Object.create(Vehicles.Vehicle()); // the function call will
// return undefined
The following would work, but it's not very Crockford-ish:
Vehicles.Airplane = Object.create(new Vehicles.Vehicle());
The way I believe Crockford would do it (or, at least, wouldn't complain of):
var Vehicles = {};
Vehicles.Vehicle = {
go : function() {
// go stuff
},
stop : function() {
// go stuff
}
};
Vehicles.Airplane = Object.create(Vehicles.Vehicle, {
takeOff : {
value : function() {
// take-off stuff
}
},
land : {
value: function() {
// land stuff
}
}
});
Note that Vehicles.Vehicle is just a literal, which will be used as the prototype for other objects. When we call Object.create, we pass Vehicles.Vehicle as the prototype, and takeOff and land will be own properties of Vehicles.Airplane. You may then call Object.create again, passing Vehicles.Airplane as the prototype, if you want to create e.g. a Boeing.
The own properties passed as the second parameter are packed in an object that contains a representation of their property descriptors. The outer keys are the names of your properties/methods, and each one points to another object containing the actual implementation as the value. You may also include other keys like enumerable; if you don't they'll take the default values. You can read more about descriptors on the MDN page about Object.defineProperty.

Javascript apply — Inheriting classes

The code below is adapted from this answer
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
ErrorMessageClass.prototype = new MessageClass();
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate());
console.log(errorB.getPrivate());
The original post did not have the MessageClass.apply(this, arguments); since the purpose was to show how inheritance can go wrong in Javascript.
My question is, is saying: ErrorMessageClass.prototype = new MessageClass(); before the ErrorMessageClass constructor has even been declared bad practice? My understanding is that calling undeclared identifiers like that causes a silent declaration to occur, with the result being placed on the global window object, which I understand is bad.
Is this form:
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
ErrorMessageClass.prototype = new MessageClass();
considered to be better practice? This link shows the code written as it was originally above, which is why I even tried it. Does this blogger know something I don't (quite likely)?
EDIT
Lots of great info in the answers below, but I did want to highlight this link which really explains things perfectly
Usually, to avoid this confusion, you would just attach the prototype after, but as Adam Rackis pointed out, function declarations are hoisted, like var statements.
However, you should not instantiate the base object as the prototype. If your base object takes arguments, what are you supposed to use? Use an empty "surrogate" constructor
// Used to setup inheritance
function surrogate () {};
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
// The key steps to creating clean inheritance
surrogate.prototype = MessageClass;
// Sets up inheritance without instantiating a base class object
ErrorMessageClass.prototype = new surrogate();
// Fix the constructor property
ErrorMessageClass.prototype.constructor = ErrorMessageClass
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
There's much more to be said. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
It works because function declarations are evaluated first. If you tried to move these classes under an object literal "namespace" the first version would fail.
I personally find the second method to be much easier to read - also, don't forget to set the sub-class' prototype.constructor property back to itself. Personally, I use an inherits() method on the Function prototype which wraps up essentially the type of code you're using here.

in javascript, how can you add / execute a new method to an object using private methods?

wish to extend define and/or execute new methods against an object using its private methods - exactly as if I were to define the method within the original declaration - except these new methods apply only to this object to be executed one time, not to the Klass itself.
for example:
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
var k = new Klass();
console.log( k.publicFn1() ); // prints 16
suppose I wish to create and/or execute a new method on Klass, sum2(), that will add 2 to the privateFn.
have tried the brain-dead
k.publicFn2 = function() { return privateFn()+2 }
console.log( k.publicFn2() );
and it makes perfect sense that it does not work, but what does?
as a note, since functions are very long, attempting to maintain the syntax of privateFn() rather than self.privateFn() - this might be asking too much, but one hopes.
There is no such thing as private in ECMAScript
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
privateFn is a local variable which publicFn1 has access to due to scoping rules (and closures).
You cannot access privateFn outside the scope of function Klass
If you want to access privateFn outside the scope of function Klass then you have to expose it through a proxy or inject it further up the scope chain.
A proxy would be something like
this._private = function() {
return privateFn;
}
Injecting further up the scope chain would be something like
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
this.uid = Klass.uid++;
Klass.instances[this.uid] = {
privateFn: privateFn
};
}
Klass.uid = 0;
Klass.instances = [];
k.publicFn2 = function() { return Klass.instances[this.uid].privateFn()+2 }
Both are ugly.
The reason they are ugly is because you are emulating classical OO
Please use prototypical OO instead.
Shameless prototypical OO plug
Javascript is a prototype-based object-oriented language. That means if you wish to user instance-specific variables, you can do it by extending the prototype object of that object. Using it any other way is unnatural and leads to problems such as yours that require an extreme hack to overcome. Why not just use the language as it was intended?
The correct structure of your code would be more like the following:
function Klass(nr) {
this.nr = nr;
};
Klass.prototype.publicFn = function() {
alert(this.nr);
};
var inst = new Klass(13);
inst.publicFn();
There are no private functions in JS and there won't be. You can "hack" the similar effect, but at the cost of either hacking something on your own or using other libraries.
It makes little sense to try to bend the language to suit you. Instead you should learn the language as it is.

Categories

Resources