I have this block of code that will create a new instance of MyClass, I want each instances of this class to have an id. So I have a function that will return cnt, and every time the new object is initialized the id value will increase.
var MyClass = (function () {
var Constr, cnt = 0;
Constr = function () {};
Constr.id = function () {
return cnt;
};
Constr.prototype = {
constructor: Constr,
id: Constr.id
};
cnt++
return Constr;
}());
var x = new MyClass();
console.log(x.id);
document.getElementById("1").innerHTML = x.id;
The problem is, I obviously want the value of cnt to be returned, but everything I do returns function() { return cnt; }
Update, deleted fiddle, posted incorrect one.
If you want each instance to have a unique value, then you need to set that value in the constructor for the instance.
You can't inherit the value on the prototype chain. That is what you do when you want every object to have the same value.
You also need to assign the value you want and not a function which will return the value.
Constr = function () {
this.id = cnd;
};
If you want the id to be uniquely assigned for each new instance of your class, then you need to assign the id to your instance data in the Const constructor:
var MyClass = (function () {
var cnt = 0;
// constructor for our object
function Constr() {
// assign a unique id to this object when it is created
this.id = cnt++;
};
// static method (not an instance method) - get current global cnt value
Constr.id = function () {
return cnt;
};
Constr.prototype = {
constructor: Constr,
};
return Constr;
}());
var x = new MyClass();
console.log(x.id);
document.getElementById("1").innerHTML = x.id;
This question shows that perhaps you didn't really understand my comments on your earlier question about the outer function only getting called once. I'd suggest you reread those.
When you do:
x = new MyClass()
it is ONLY executing the Constr function, nothing else. Plus, the .prototype is shared among all instances (that is the point of it) so you can never put a counter there that is unique for each instance.
It seem like all You need is:
var MyClass = (function () {
var cnt = 0;
function Constr() {
this.id = cnt++;
};
Constr.prototype = {
constructor: Constr
};
return Constr;
}());
The following one was my previous BAD answer,
You could replace Constr.id with:
....
Constr.id = new function () {
this.toString = function () {
return ++cnt;
}
};
....
and then You should get it from the instance with
var x = new MyClass();
console.debug(x.id);
but take care that it will be an object and only when used as a string, (like in console.debug, or with .innerHTML= "..." ) will be a string.
Hope it helps.
Related
I want to create a method which automatically implemented when create an instance of an object, exactly like concept of class constructor.
function myString(string) {
// Storing the length of the string.
this.length = 0;
// A private constructor which automatically implemented
var __construct = function() {
this.getLength();
}();
// Calculates the length of a string
this.getLength = function() {
for (var count in string) {
this.length++;
}
};
}
// Implementation
var newStr = new myString("Hello");
document.write(newStr.length);
I have the following error message when implement the previous code:
TypeError: this.getLength is not a function.
UPDATE:
The problem was in this scope.
The following is constructor method after updade:
var __construct = function(that) {
that.getLength();
}(this);
Bergi's answer in this thread is far more relevant: How to define private constructors in javascript?
Though a bit crude you can create a method called init and then call that method at the bottom of your function so when you instantiate a new object that code shall be run.
function myString(string) {
//Initalization function
this.init = function() {
this.calcLength();
}
// Storing the length of the string.
this.length = 0;
this.getLength = function() {
return this.length;
}
// Calculates the length of a string
this.calcLength = function() {
for (var count in string) {
this.length++;
}
};
this.init();
}
// Implementation
var newStr = new myString("Hello");
var element = document.getElementById('example');
element.innerText = newStr.getLength();
Edit: I'm aware there are better ways to achieve this, but this gets the job done.
Edit 2: Fiddle https://jsfiddle.net/ntygbfb6/3/
I try to follow Stephan Stoyanov book on JavaScript Design Patterns. And one of the examples in this book looks similar to this:
var MyClass = (function () {
var Constr, cnt = 0;
Constr = function () {};
Constr.id = function () {
return "myid-" + cnt;
};
Constr.prototype = {
constructor: MyClass // <-- Please, pay attention
};
return Constr;
}());
However, when I use this code like so:
var tst = new MyClass();
console.log(tst.contructor);
I see undefined in the console. Why is that and how can I fix that?
At the point you assign MyClass to the .constructor property of the prototype, the variable MyClass has not yet been initialized. It won't have a value until after your function is done executing. Instead, you can just assign it Constr since that does have a value and they will be the same value that is eventually assigned to MyClass.
var MyClass = (function () {
var Constr, cnt = 0;
Constr = function () {};
Constr.id = function () {
return "myid-" + cnt;
};
Constr.prototype = {
constructor: Constr // <-- Change to this
};
return Constr;
}());
The problem is here:
Constr.prototype = {
constructor: MyClass // MyClass is undefined right now!
};
The function hasn't completed when it assigns MyClass as the value for the constructor property. At this point MyClass is undefined, so that's what you get.
See this: https://jsfiddle.net/vh45can8/
As written Constr is an anonymous function which already has its prototype object's constructor pointing to itself. I hope the book gives a reason for making things complicated:
var MyClass = (function () {
var Constr, cnt = 0;
Constr = function () {};
Constr.id = function () {
return "myid-" + cnt;
};
return Constr;
}());
works without serious mystery.
I have a method in a base class that I want to keep in a subclass, but just add to it. I've found lots of stuff on augmenting classes and objects with properties and methods, but I can't find, or don't understand, how to just augment the method. The worst case scenario is that I would have to paste the entire method of the parent class into the subclass, but that seems like duplicate code... please help
function someObject (){
this.someProperty = 1;
this.incrementProperty = function incrementProperty(){
this.propertyOfSomeObject += 1;
}
}
function newObject (){
someObject.call(this);
this.incrementProperty = function incrementProperty(){
//do everything the super class has for this property already
return this.someProperty;
}
}
var incrementer = new newObject;
alert (incrementer.incrementProperty()); //I want output to be 2
// parent object
function someObject () {
this.someProperty = 1;
}
// add incrementProperty to the prototype so you're not creating a new function
// every time you instantiate the object
someObject.prototype.incrementProperty = function() {
this.someProperty += 1;
return this.someProperty;
}
// child object
function newObject () {
// we could do useful work here
}
// setup new object as a child class of someObject
newObject.prototype = new someObject();
// this allows us to use "parent" to call someObject's functions
newObject.prototype.parent = someObject.prototype;
// make sure the constructor points to the right place (not someObject)
newObject.constructor = newObject;
newObject.prototype.incrementProperty = function() {
// do everything the super class has for this property already
this.parent.incrementProperty.call(this);
return this.someProperty;
}
var incrementer = new newObject();
alert (incrementer.incrementProperty()); // I want output to be 2
See: http://jsfiddle.net/J7RhA/
this should do, you have to use prototype to have a real concept of oo with javascript
function someObject (){
this.someProperty = 1;
this.propertyOfSomeObject = 0;
this.incrementProperty = function incrementProperty(){
this.propertyOfSomeObject += 1;
return this.propertyOfSomeObject;
}
}
function newObject (){
someObject.call(this);
this.incrementProperty = function incrementProperty(){
this.__super__.incrementProperty.apply(this);
return this.propertyOfSomeObject + 1;
}
}
newObject.prototype = new someObject()
newObject.prototype.__super__ = newObject.prototype
var incrementer = new newObject();
alert(incrementer.incrementProperty()); //I want output to be 2
experiment removing incrementProperty from newObject and it will return 1
I usually use the augment library to write classes in JavaScript. This is how I would rewrite your code using augment:
var Foo = Object.augment(function () {
this.constructor = function () {
this.someProperty = 1;
};
this.incrementProperty = function () {
this.someProperty++;
};
});
var Bar = Foo.augment(function (base) {
this.constructor = function () {
base.constructor.call(this);
};
this.incrementProperty = function () {
base.incrementProperty.call(this);
return this.someProperty;
};
});
As you can see since Bar extends Foo it gets Foo.prototype as a parameter (which we call base). This allows you to easily call the base class constructor and incrementProperty functions. It also shows that the constructor itself is just another method defined on the prototype.
var bar = new Bar;
alert(bar.incrementProperty());
The output will be 2 as expected. See the demo for yourself: http://jsfiddle.net/47gmQ/
From this answer:
Overriding functions
Sometimes children need to extend parent functions.
You want the 'child' (=RussionMini) to do something extra. When RussionMini can call the Hamster code to do something and then do something extra you don't need to copy and paste Hamster code to RussionMini.
In the following example we assume that a Hamster can run 3km an hour but a Russion mini can only run half as fast. We can hard code 3/2 in RussionMini but if this value were to change we have multiple places in code where it needs changing. Here is how we use Hamster.prototype to get the parent (Hamster) speed.
// from goog.inherits in closure library
var inherits = function(childCtor, parentCtor) {
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};
var Hamster = function(name){
if(name===undefined){
throw new Error("Name cannot be undefined");
}
this.name=name;
}
Hamster.prototype.getSpeed=function(){
return 3;
}
Hamster.prototype.run=function(){
//Russionmini does not need to implement this function as
//it will do exactly the same as it does for Hamster
//But Russionmini does need to implement getSpeed as it
//won't return the same as Hamster (see later in the code)
return "I am running at " +
this.getSpeed() + "km an hour.";
}
var RussionMini=function(name){
Hamster.apply(this,arguments);
}
//call this before setting RussionMini prototypes
inherits(RussionMini,Hamster);
RussionMini.prototype.getSpeed=function(){
return Hamster.prototype
.getSpeed.call(this)/2;
}
var betty=new RussionMini("Betty");
console.log(betty.run());//=I am running at 1.5km an hour.
I want extend a new JS object while creation with other object passing a parameter.
This code does not work, because I only can extend object without dynamic parameter.
otherObject = function(id1){
this.id = id1;
};
otherObject.prototype.test =function(){
alert(this.id);
};
testObject = function(id2) {
this.id=id2;
};
testObject.prototype = new otherObject("id2");/* id2 should be testObject this.id */
var a = new testObject("variable");
a.test();
Any suggestion?
Apart from the obvious syntax error, the correct JavaScript way of inheritance is this:
// constructors are named uppercase by convention
function OtherObject(id1) {
this.id = id1;
};
OtherObject.prototype.test = function() {
alert(this.id);
};
function TestObject(id2) {
// call "super" constructor on this object:
OtherObject.call(this, id2);
};
// create a prototype object inheriting from the other one
TestObject.prototype = Object.create(OtherObject.prototype);
// if you want them to be equal (share all methods), you can simply use
TestObject.prototype = OtherObject.prototype;
var a = new TestObject("variable");
a.test(); // alerts "variable"
You will find lots of tutorials about this on the web.
Fixed your code
otherObject = function(id1){
this.id = id1;
};
otherObject.prototype.test =function(){
alert(this.id);
};
testObject = function(id2) {
this.id=id2;
};
testObject.prototype = new otherObject("id2");/* id2 should be testObject this.id */
var a = new testObject("variable");
a.test();
testObject = function(id2) {
otherObject.call(this, id2); // run the parent object constructor with id2 parameter
this.id=id2;
};
testObject.prototype = new otherObject(); // no id2 parameter here, it doesn't make sense
Note that while creating an instance of testObject, the constructor of otherObject is called twice - once to create the prototype and once to initialise the object.
To prevent duplicate initialisation, we can halt the constructor immediately when we are only using it to create the prototype.
otherObject = function(id1){
if (typeof id1 == 'undefined') {
/* as there is no parameter, this must be the call used to create
* the prototype. No initialisation needed here, we'll just return.
*/
return;
}
this.id = id1;
};
P.S. Please use capital camelcase with objects.
I do not understand exactly what you desire, but
otherObject.prototype.test = function () {
alert(this.id);
};
would be correct.
And this
testObject.prototype = new otherObject(id2);
will not work unless id2 is set before.
Try the following
var OtherObject = function () {
}
OtherObject.prototype.test = function () {
alert (this.id);
}
var TestObject = function (id) {
this.id = id;
}
TestObject.prototype = new OtherObject ();
var a = new TestObject("variable");
a.test ();
Is it possible in javascript to have a variable that is not able to access out side the class's functions, but is able to be accessed by classes that inherit it? I.E:
class1 has protected var x = 4;
class2 inherits class1;
class2.prototype.getVar = function(){return /* parent, uber, super, whatever */ this.x;};
var cl2 = new class2();
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
No. Prototypal inheritance is limited to properties of objects.
Variables within the constructor are only available to other code in that variable scope.
You could probably come up with something like...
function cls1() {
var a = 'foo';
this.some_func = function() {
alert(a);
};
}
function cls2() {
cls1.apply(this, arguments);
var cls1_func = this.some_func;
var b = 'bar'
this.some_func = function() {
cls1_func.apply(this, arguments);
alert(b);
};
}
var x = new cls2;
x.some_func(); // alert "foo" alert "bar"
Or to make it more specific to your pseudo code...
function class1() {
var x = 4;
this.getVar = function() {
return x;
};
}
function class2() {
class1.apply(this, arguments);
var cls1_get_var = this.getVar;
this.getVar = function() {
return cls1_get_var.apply(this, arguments);
};
}
class2.prototype = Object.create( class1.prototype );
var cl2 = new class2;
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
I think you need to use a closure to achieve what your trying to do. Something like this:
Class1 = function() {
var x = 4;
return {
getVar: function() {
return x;
}
}
} ();// executes the function immediately and returns an
//an object with one method - getVar. Through closure this method
//still has access to the variable x
Class2 = function() { };// define a constructor function
Class2.prototype = Class1;//have it inherit from Class1
Cl2 = new Class2();//instantiate a new instance of Class2
console.log(Cl2.x);//this is undefined
console.log(Cl2.getVar());//this outputs 4
This is one of the neat things about javascript in that you can achieve the same things in javascript as you would in a class based language without all the extra key words. Douglas Crockford (always good to consult about javascript) explains prototypal inheritance here
Edit:
Just had a second look at your question.If you want newly created methods in your class to access the variable in the base class then you would have to call the getVar method within your own method.Like such:
Class2 = function() {
this.getVar2 = function() {
return this.getVar();
}
};
console.log(Cl2.getVar2()) //outputs 4