I created a construction function which will create simple video-game character. The constructor takes name as argument and set to property hName. The constructed object have other properties, like speed, defaultEnergy, energyUsed and so on (see code). Also, I have two methods inside the constructor function, description and energyLevel. I want to use energyLevel function as callback to description function.
The parse error is on line this.hName: name,
Here is the JavaScript code:
var superHero = function (name) {
this.hName: name,
speed: 7,
defaultEnergy: 20,
energyUsed: 10,
flyAbility: true,
description: function (energyLevel) {
document.write(this.name + " has the capability to hold the hummer.");
energyLevel();
},
energyLevel = function () {
return ("<br>Current energy level is " + (this.defaultEnergy - this.energyUsed));
}
};
hero = new superHero("Thor");
document.write(hero.description());
I want the following result:
Thor has the capability to hold the hummer.
Current energy level is 10
I know, it could be achieved very easily without using callback function. But I want to achieve it with callback because I need it in my rest of project, and will also help me to understand why callback is not working.
When you call new Foo, an object is created for you and accessible from within the body of your function. In order to add properties to that object, you use the keyword this:
function SuperHero ( name ) {
this.hName = name;
}
var hero = new SuperHero( "Thor" );
console.log( `Name: ${hero.hName}.` );
You may also want to put much of this on the function's prototype:
function SuperHero ( name ) {
this.hName = name;
this.energyLevels = 10;
}
SuperHero.prototype = {
energyLevel: function () {
document.write( `Current energy level is ${this.energyLevels}.` );
},
description: function ( energyLevel ) {
document.write( `${this.hName} has a description.` );
this.energyLevel();
}
};
Items placed on the SuperHero.prototype object will be shared between all instances of SuperHero.
For further reading, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new#Description.
You want to create a superHero class? Use prototype for class methods and this.mymember = value; in the constructor for internal variables. Example:
// class superHero
var superHero = function superHero(name) {
this.hName = name;
this.speed = 7;
this.defaultEnergy = 20;
this.energyUsed = 10;
this.flyAbility = true;
};
superHero.prototype.description = function description() {
document.write(this.hName + " has the capability to hold the hammer.");
return this.energyLevel();
};
superHero.prototype.energyLevel = function energyLevel() {
return "<br>Current energy level is " + (this.defaultEnergy - this.energyUsed);
};
// Example
var hero = new superHero("Thor");
document.write(hero.description());
The way you're trying to assign values doesn't work. Try to rewrite to this:
var superHero = function (name) {
this.name = name;
this.speed = 7;
this.defaultEnergy = 20;
this.energyUsed = 10;
this.flyAbility = true;
};
superHero.prototype = {
description: function (energyLevel) {
document.write(this.name + " has the capability to hold the hummer.");
document.write(this.energyLevel());
},
energyLevel : function () {
return ("<br>Current energy level is " + (this.defaultEnergy - this.energyUsed));
}
}
var hero = new superHero("Thor").description();
DEMO
It needs to be changed to this for every single property
var superHero = function (name) {
this.hName = name;
this.description = function (energyLevel) {
document.write(this.name + " has the capability to hold the hummer.");
energyLevel();
};
};
What you're trying to do works for Object creation, but not if you want to create a constructor function.
This object is completely invalid. You need to choose between a function or an object literal and you're mixing both of these together.
Using an object literal you do this:
var superHero = {
name: null,
speed: 7,
defaultEnergy: 20,
energyUsed: 10,
flyAbility: true,
description: function (energyLevel) {
document.write(superHero.name + " has the capability to hold the hummer.");
superHero.energyLevel();
},
energyLevel: function () {
return ("<br>Current energy level is " + (superHero.defaultEnergy - superHero.energyUsed));
}
};
//hero = new superHero("Thor");
superHero.name = "Thor";
superHero.description(10);
Using a function/class you can do this:
var superHero = function(name) {
self = this;
this.name= name;
this.speed= 7;
defaultEnergy= 20;
energyUsed = 10;
flyAbility = true;
this.description = function (energyLevel) {
document.write(self.name + " has the capability to hold the hummer.");
self.energyLevel();
};
this.energyLevel = function () {
return ("<br>Current energy level is " + (selfHero.defaultEnergy - self.energyUsed));
};
};
hero = new superHero("Thor");
hero.description(10);
If it helps you can think of object literals as static object instances and functions as dynamic instances you create more of.
You have to use word 'this' to show what you are working with properties and methods of this current instance of the Constructor function.
this.hName = name;
and when you call method inside...
this.energyLevel();
i want to functionality something similar to get property of C# .net. for example
var method : function() {
return "something which always change";
},
var objectName = {
property : method()
};
so whenever i call objectName.property this should return the actual new values. not the value set at the time of declaration. is it possible.
In .net property hold the function address and that function get called each time. i want the functionality like that.
thanks,
Use Object.defineProperty to override the getter.
var counter = 0;
var method = function() {
return counter++;
};
function ObjectName() {}
Object.defineProperty(ObjectName.prototype, 'property', {
get: method
});
var objectName = new ObjectName();
console.log(objectName.property); // 0
console.log(objectName.property); // 1
JSBin Demo https://jsbin.com/racegeteni/edit?js,console
other way to write this in more like a .net c# style is
var o = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
console.log(o.a); // 7
console.log(o.b); // 8
o.c = 50;
console.log(o.a); // 25
For OOP reasons, you should treat an object as a Class in .Net.
For example:
var Superman = function () {
this.quality = 'charming';
this.height = "6'5\"";
this.fly = function() {
console.log('flying..');
}
this.save = function(name) {
console.log('Save ' + name);
}
return this;
};
var CK = Superman();
console.log(CK.quality);
CK.save('L. Lane');
Can JavaScript classes/objects have constructors? How are they created?
Using prototypes:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Hiding "color" (somewhat resembles a private member variable):
function Box(col)
{
var color = col;
this.getColor = function()
{
return color;
};
}
Usage:
var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue
var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
Here's a template I sometimes use for OOP-similar behavior in JavaScript. As you can see, you can simulate private (both static and instance) members using closures. What new MyClass() will return is an object with only the properties assigned to the this object and in the prototype object of the "class."
var MyClass = (function () {
// private static
var nextId = 1;
// constructor
var cls = function () {
// private
var id = nextId++;
var name = 'Unknown';
// public (this instance only)
this.get_id = function () { return id; };
this.get_name = function () { return name; };
this.set_name = function (value) {
if (typeof value != 'string')
throw 'Name must be a string';
if (value.length < 2 || value.length > 20)
throw 'Name must be 2-20 characters long.';
name = value;
};
};
// public static
cls.get_nextId = function () {
return nextId;
};
// public (shared across instances)
cls.prototype = {
announce: function () {
alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
}
};
return cls;
})();
I've been asked about inheritance using this pattern, so here goes:
// It's a good idea to have a utility class to wire up inheritance.
function inherit(cls, superCls) {
// We use an intermediary empty constructor to create an
// inheritance chain, because using the super class' constructor
// might have side effects.
var construct = function () {};
construct.prototype = superCls.prototype;
cls.prototype = new construct;
cls.prototype.constructor = cls;
cls.super = superCls;
}
var MyChildClass = (function () {
// constructor
var cls = function (surName) {
// Call super constructor on this instance (any arguments
// to the constructor would go after "this" in call(…)).
this.constructor.super.call(this);
// Shadowing instance properties is a little bit less
// intuitive, but can be done:
var getName = this.get_name;
// public (this instance only)
this.get_name = function () {
return getName.call(this) + ' ' + surName;
};
};
inherit(cls, MyClass); // <-- important!
return cls;
})();
And an example to use it all:
var bob = new MyClass();
bob.set_name('Bob');
bob.announce(); // id is 1, name shows as "Bob"
var john = new MyChildClass('Doe');
john.set_name('John');
john.announce(); // id is 2, name shows as "John Doe"
alert(john instanceof MyClass); // true
As you can see, the classes correctly interact with each other (they share the static id from MyClass, the announce method uses the correct get_name method, etc.)
One thing to note is the need to shadow instance properties. You can actually make the inherit function go through all instance properties (using hasOwnProperty) that are functions, and automagically add a super_<method name> property. This would let you call this.super_get_name() instead of storing it in a temporary value and calling it bound using call.
For methods on the prototype you don't need to worry about the above though, if you want to access the super class' prototype methods, you can just call this.constructor.super.prototype.methodName. If you want to make it less verbose you can of course add convenience properties. :)
It seems to me most of you are giving example of getters and setters not a constructor, ie http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming).
lunched-dan was closer but the example didn't work in jsFiddle.
This example creates a private constructor function that only runs during the creation of the object.
var color = 'black';
function Box()
{
// private property
var color = '';
// private constructor
var __construct = function() {
alert("Object Created.");
color = 'green';
}()
// getter
this.getColor = function() {
return color;
}
// setter
this.setColor = function(data) {
color = data;
}
}
var b = new Box();
alert(b.getColor()); // should be green
b.setColor('orange');
alert(b.getColor()); // should be orange
alert(color); // should be black
If you wanted to assign public properties then the constructor could be defined as such:
var color = 'black';
function Box()
{
// public property
this.color = '';
// private constructor
var __construct = function(that) {
alert("Object Created.");
that.color = 'green';
}(this)
// getter
this.getColor = function() {
return this.color;
}
// setter
this.setColor = function(color) {
this.color = color;
}
}
var b = new Box();
alert(b.getColor()); // should be green
b.setColor('orange');
alert(b.getColor()); // should be orange
alert(color); // should be black
So what is the point of "constructor"
property? Cannot figure out where it
could be useful, any ideas?
The point of the constructor property is to provide some way of pretending JavaScript has classes. One of the things you cannot usefully do is change an object's constructor after it's been created. It's complicated.
I wrote a fairly comprehensive piece on it a few years ago: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Example here: http://jsfiddle.net/FZ5nC/
Try this template:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Name = Name||{};
Name.Space = Name.Space||{};
//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Name.Space.ClassName = function Name_Space_ClassName(){}
//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Name.Space.ClassName.prototype = {
v1: null
,v2: null
,f1: function Name_Space_ClassName_f1(){}
}
//============================================================
// Static Variables
//------------------------------------------------------------
Name.Space.ClassName.staticVar = 0;
//============================================================
// Static Functions
//------------------------------------------------------------
Name.Space.ClassName.staticFunc = function Name_Space_ClassName_staticFunc(){
}
</script>
You must adjust your namespace if you are defining a static class:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Example class:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Shape.Rectangle = function Shape_Rectangle(width, height, color){
this.Width = width;
this.Height = height;
this.Color = color;
}
//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Shape.Rectangle.prototype = {
Width: null
,Height: null
,Color: null
,Draw: function Shape_Rectangle_Draw(canvasId, x, y){
var canvas = document.getElementById(canvasId);
var context = canvas.getContext("2d");
context.fillStyle = this.Color;
context.fillRect(x, y, this.Width, this.Height);
}
}
//============================================================
// Static Variables
//------------------------------------------------------------
Shape.Rectangle.Sides = 4;
//============================================================
// Static Functions
//------------------------------------------------------------
Shape.Rectangle.CreateSmallBlue = function Shape_Rectangle_CreateSmallBlue(){
return new Shape.Rectangle(5,8,'#0000ff');
}
Shape.Rectangle.CreateBigRed = function Shape_Rectangle_CreateBigRed(){
return new Shape.Rectangle(50,25,'#ff0000');
}
</script>
Example instantiation:
<canvas id="painting" width="500" height="500"></canvas>
<script>
alert("A rectangle has "+Shape.Rectangle.Sides+" sides.");
var r1 = new Shape.Rectangle(16, 12, "#aa22cc");
r1.Draw("painting",0, 20);
var r2 = Shape.Rectangle.CreateSmallBlue();
r2.Draw("painting", 0, 0);
Shape.Rectangle.CreateBigRed().Draw("painting", 10, 0);
</script>
Notice functions are defined as A.B = function A_B(). This is to make your script easier to debug. Open Chrome's Inspect Element panel, run this script, and expand the debug backtrace:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
This is a constructor:
function MyClass() {}
When you do
var myObj = new MyClass();
MyClass is executed, and a new object is returned of that class.
Yes, you can define a constructor inside a class declaration like this:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
I found this tutorial very useful. This approach is used by most of jQuery plug-ins.
http://www.htmlgoodies.com/html5/tutorials/create-an-object-oriented-javascript-class-constructor.html#fbid=OVYAQL_TDpK
var Class = function(methods) {
var klass = function() {
this.initialize.apply(this, arguments);
};
for (var property in methods) {
klass.prototype[property] = methods[property];
}
if (!klass.prototype.initialize) klass.prototype.initialize = function(){};
return klass;
};
Now ,
var Person = Class({
initialize: function(name, age) {
this.name = name;
this.age = age;
},
toString: function() {
return "My name is "+this.name+" and I am "+this.age+" years old.";
}
});
var alice = new Person('Alice', 26);
alert(alice.name); //displays "Alice"
alert(alice.age); //displays "26"
alert(alice.toString()); //displays "My name is Alice and I am 26 years old" in most browsers.
//IE 8 and below display the Object's toString() instead! "[Object object]"
This pattern has served me well. With this pattern, you create classes in separate files, load them into your overall app "as needed".
// Namespace
// (Creating new if not instantiated yet, otherwise, use existing and just add to it)
var myApp = myApp || {};
// "Package"
// Similar to how you would establish a package in other languages
(function() {
// "Class"
var MyClass = function(params) {
this.initialize(params);
}
// "Private Static" vars
// - Only accessible to functions in this class.
// - Doesn't get wiped out when we create a new instance.
var countInstances = 0;
var allInstances = [];
// "Private Static" functions
// - Same as above, but it's a function accessible
// only to other functions in this class.
function doSomething(){
}
// "Public Static" vars
// - Everyone has access.
// - Doesn't get wiped out when we create a new instance.
MyClass.counter = 0;
// "Public Static" functions
// - Same as above, but anyone can call this "static method".
// - Kinda like a singleton class situation.
MyClass.foobar = function(){
}
// Public properties and methods are built into the "prototype"
// - This is how each instance can become unique unto itself.
// - Establishing "p" as "local" (Static Private) variable
// simply so we don't have to keep typing "MyClass.prototype"
// for each property and function.
var p = MyClass.prototype;
// "Public" vars
p.id = null;
p.firstname = null;
p.lastname = null;
// "Private" vars
// - Only used by "this" instance.
// - There isn't "true" privacy for each
// instance so we have to fake it.
// - By tradition, we indicate "privacy"
// by prefixing it with an underscore.
// - So technically, anyone can access, but we simply
// don't tell anyone about it (e.g. in your API)
// so no one knows about it :)
p._foo = null;
p.initialize = function(params){
this.id = MyClass.counter++;
this.firstname = params.firstname;
this.lastname = params.lastname;
MyClass.counter++;
countInstances++;
allInstances.push(this);
}
p.doAlert = function(theMessage){
alert(this.firstname + " " + this.lastname + " said: " + theMessage + ". My id:" + this.id + ". Total People:" + countInstances + ". First Person:" + allInstances[0].firstname + " " + allInstances[0].lastname);
}
// Assign class to app
myApp.MyClass = MyClass;
// Close the "Package"
}());
// Usage example:
var bob = new myApp.MyClass({ firstname : "bob",
lastname : "er"
});
bob.doAlert("hello there");
I guess I'll post what I do with javascript closure since no one is using closure yet.
var user = function(id) {
// private properties & methods goes here.
var someValue;
function doSomething(data) {
someValue = data;
};
// constructor goes here.
if (!id) return null;
// public properties & methods goes here.
return {
id: id,
method: function(params) {
doSomething(params);
}
};
};
Comments and suggestions to this solution are welcome. :)
Maybe it's gotten a little simpler, but below is what I've come up with now in 2017:
class obj {
constructor(in_shape, in_color){
this.shape = in_shape;
this.color = in_color;
}
getInfo(){
return this.shape + ' and ' + this.color;
}
setShape(in_shape){
this.shape = in_shape;
}
setColor(in_color){
this.color = in_color;
}
}
In using the class above, I have the following:
var newobj = new obj('square', 'blue');
//Here, we expect to see 'square and blue'
console.log(newobj.getInfo());
newobj.setColor('white');
newobj.setShape('sphere');
//Since we've set new color and shape, we expect the following: 'sphere and white'
console.log(newobj.getInfo());
As you can see, the constructor takes in two parameters, and we set the object's properties. We also alter the object's color and shape by using the setter functions, and prove that its change remained upon calling getInfo() after these changes.
A bit late, but I hope this helps. I've tested this with a mocha unit-testing, and it's working well.
Using Nick's sample above, you can create a constructor for objects without parameters using a return statement as the last statement in your object definition. Return your constructor function as below and it will run the code in __construct each time you create the object:
function Box()
{
var __construct = function() {
alert("Object Created.");
this.color = 'green';
}
this.color = '';
this.getColor = function() {
return this.color;
}
__construct();
}
var b = new Box();
They do if you use Typescript - open source from MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
Typescript lets you 'fake' OO constructs that are compiled into javascript constructs. If you're starting a large project it may save you a lot of time and it just reached milestone 1.0 version.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
The above code gets 'compiled' to :
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
In JavaScript the invocation type defines the behaviour of the function:
Direct invocation func()
Method invocation on an object obj.func()
Constructor invocation new func()
Indirect invocation func.call() or func.apply()
The function is invoked as a constructor when calling using new operator:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
Any instance or prototype object in JavaScript have a property constructor, which refers to the constructor function.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Check this post about constructor property.
While using Blixt's great template from above, I found out that it doesn't work well with multi-level inheritance (MyGrandChildClass extending MyChildClass extending MyClass) – it cycles on calling first parent's constructor over and over. So here is a simple workaround – if you need multi-level inheritance, instead of using this.constructor.super.call(this, surName); use chainSuper(this).call(this, surName); with the chain function defined like this:
function chainSuper(cls) {
if (cls.__depth == undefined) cls.__depth = 1; else cls.__depth++;
var depth = cls.__depth;
var sup = cls.constructor.super;
while (depth > 1) {
if (sup.super != undefined) sup = sup.super;
depth--;
}
return sup;
}
http://www.jsoops.net/ is quite good for oop in Js. If provide private, protected, public variable and function, and also Inheritance feature. Example Code:
var ClassA = JsOops(function (pri, pro, pub)
{// pri = private, pro = protected, pub = public
pri.className = "I am A ";
this.init = function (var1)// constructor
{
pri.className += var1;
}
pub.getData = function ()
{
return "ClassA(Top=" + pro.getClassName() + ", This=" + pri.getClassName()
+ ", ID=" + pro.getClassId() + ")";
}
pri.getClassName = function () { return pri.className; }
pro.getClassName = function () { return pri.className; }
pro.getClassId = function () { return 1; }
});
var newA = new ClassA("Class");
//***Access public function
console.log(typeof (newA.getData));
// function
console.log(newA.getData());
// ClassA(Top=I am A Class, This=I am A Class, ID=1)
//***You can not access constructor, private and protected function
console.log(typeof (newA.init)); // undefined
console.log(typeof (newA.className)); // undefined
console.log(typeof (newA.pro)); // undefined
console.log(typeof (newA.getClassName)); // undefined
just to offer up some variety. ds.oop is a nice way to declare classes with constructors in javascript. It supports every possible type of inheritance (Including 1 type that even c# does not support) as well as Interfaces which is nice.
var Color = ds.make.class({
type: 'Color',
constructor: function (r,g,b) {
this.r = r; /* now r,g, and b are available to */
this.g = g; /* other methods in the Color class */
this.b = b;
}
});
var red = new Color(255,0,0); // using the new keyword to instantiate the class
Here we need to notice one point in java script, it is a class-less language however,we can achieve it by using functions in java script. The most common way to achieve this we need to create a function in java script and use new keyword to create an object and use this keyword to define property and methods.Below is the example.
// Function constructor
var calculator=function(num1 ,num2){
this.name="This is function constructor";
this.mulFunc=function(){
return num1*num2
};
};
var objCal=new calculator(10,10);// This is a constructor in java script
alert(objCal.mulFunc());// method call
alert(objCal.name);// property call
//Constructors With Prototypes
var calculator=function(){
this.name="Constructors With Prototypes";
};
calculator.prototype.mulFunc=function(num1 ,num2){
return num1*num2;
};
var objCal=new calculator();// This is a constructor in java script
alert(objCal.mulFunc(10,10));// method call
alert(objCal.name); // property call
In most cases you have to somehow declare the property you need before you can call a method that passes in this information. If you do not have to initially set a property you can just call a method within the object like so. Probably not the most pretty way of doing this but this still works.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();
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);
My question is... in CallMeLaterTestObj function in the TestObj the "this" is the window object and not TestObj. How can I restructure this so that within the CallMeLater function I don't have to wrap the call function() { v.CallMeLaterTestObj(); } in a closure or using the bind function since it has limited support to newer browsers. Two objectives:
Keeping "this" in function calls within the object
Maintaining a separate value for "value" for each separate object so they don't share the same value.
// Emulating public api, private methods, private variables, public fields.
// New portion of question
Re-written to include binding function and prototypical notation. How do you move the Binding function into a base object that all new objects would get?
This is as close as I can come to getting this to use the best of both worlds. I have no idea what the pitfalls of this approach are though
var BaseObject = function ()
{
_getBinding = function (method)
{
var _self = this;
return function ()
{
_self[method].apply(_self, arguments);
};
};
return {
CallInline: _getBinding
}
}();
var TestObj = function (value)
{
$.extend(this, BaseObject);
// public var
this._value = value;
};
TestObj.prototype = function()
{
var privateVar = false;
// these are private
_giveMe = function () {
return this._value;
},
_callMeLaterTestObj = function () {
console.log('I am ' + this.constructor.name + ' my value is ' + this._value);
};
// public API
return {
GiveMe : _giveMe,
CallMeLaterTestObj : _callMeLaterTestObj
}
}();
function CallMeLater(v, i)
{
setTimeout(v.CallInline('CallMeLaterTestObj'), 10);
}
var V1 = new TestObj(1);
var V2 = new TestObj(2);
var V3 = new TestObj(3);
console.log('V1= ' + V1.GiveMe());
console.log('V2= ' + V2.GiveMe());
console.log('V3= ' + V3.GiveMe());
console.log('---');
V1.CallMeLaterTestObj();
console.log('---');
I think what you're looking for is this:
function TestObj(value) {
var _value = value;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
return this;
};
function callMeLater(v, i) {
setTimeout(function() {
v.callMeLaterTestObj();
}, 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);
To access constructor.name, you need to declare the function with function name() syntax, rather than var name = function() syntax.
To keep private variables and expose a public api, expose the public variables as properties of this in the function.
Be sure to return this from the constructor function to make it work.
It's also good practice to follow the naming convention of CamelCase for class names (of which TestObj is one) and lowerCamelCase for variables / methods / objects / etc. Helps keep things clear as to which variables are instances, and which are Classes.
Test and see the console output expected here.
note
Regarding wrapping v.callMeLaterTestObj() in a closure for the setTimeout, this technique is completely cross-browser compatible. You won't have any issues.
The bind method is newer, although there are many libraries that will shim that for you in older browsers. My personal favourite is underscore.
note 2
You can't call a method on an object in setTimeout without wrapping it in a closure somewhere, however if you want to you can abstract the closure in the Class without using a generic bind function (as provided by Underscore or jQuery and others) you can 'roll your own' in the Class like this:
function TestObj(value) {
var _value = value;
var _self = this;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
this.getBinding = function(method) {
var _self = this;
return function() {
_self[method].apply(_self, arguments);
};
};
return this;
};
function callMeLater(v, i) {
setTimeout(v.getBinding('callMeLaterTestObj'), 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);
explanation:
You need to use some sort of binding because, when you pass the method to setTimeout, you pass it by reference. So all setTimeout sees is a function - not the object it was on, which is why you lose the context of this.
Since setTimeout will therefore execute the function in the default scope - i.e. the browser window - you need a way to get this back, by reference, either through an inline anonymous function, or by returning a closure that uses the apply method to 'reset' this.
note 3
If you wanted to have your own bind method, and not include a library that provides it for you or include it in every class then you can use this one from Underscore, which defers to the native method in newer browsers:
function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
Then use it like this:
function callMeLater(v, i) {
setTimeout(bind(v.callMeLaterTestObj, v), 10);
}
This will work well in all browsers.
No, you can't. That's just the way to do it. Btw, you can easily shim the bind method so that it is available in older browsers, too.
An alternative would be to move the closure into the prototype method, if you know that you always will need to bind the actual function:
TestObj.prototype.getCallMeLaterTestObj = function () {
var that = this;
return function() {
console.log('I am ' + that.constructor.name + ' my value is ' + that._value);
};
};
setTimeout(v.getCallMeLaterTestObj(), 10);
Btw, your prototype has no constructor property so the log will not work as expected.
Your only chance is to avoid the this keyword entirely:
TestObj = function() {
var privateVar = false; // these are private static
function TestObj(value) {
function giveMe() {
return value;
}
function callMeLaterTestObj() {
console.log('I am TestObj my value is ' + giveMe());
}
this._value = value;
this.giveMe = giveMe;
this.callMeLaterTestObj = callMeLaterTestObj;
/* you could do this as well:
return {
_value: value,
giveMe: giveMe,
callMeLaterTestObj: callMeLaterTestObj
}; */
}
return TestObj;
})();
var v = new TestObj;
setTimeout(v.callMeLater, 10);
But this is not very memory-efficient, as it does not use prototypical inheritance at all.