Okay, so I want to create a constructor function in javascript which will count the total number of instances which are created using this constructor.
var Component = function(name) {
this.name = name;
this.add = function(){this.prototype.countInstances++;};
this.add();
};
and
Component.prototype.countInstances=0;
As I understand it correctly, the countInstances variable is added to the prototype and will act like a static copy for all the instances and will act as my counter.
The problem with this code is that since I'm declaring the countInstances after the constructor, I'm getting an error in the constructor code itself. How to correct this??
If you'd like a property to be attached to the class itself, and not instances of the class, you don't want to add the property to prototype:
var Component = function(name) {
this.name = name;
Component.instanceCount++;
};
Component.instanceCount = 0;
This way, you're assigning each name to its instance, and the total instance count to the static class:
var foo = new Component('bar');
var baz = new Component('qux');
console.info(foo.name, baz.name, Component.instanceCount);
>> 'bar', 'qux', 2
As I understand it correctly, the countInstances variable is added to the prototype and will act like a static copy for all the instances and will act as my counter.
No, it will be, in effect, a default value for instances, not a "static." If you put it on Component.prototype, all instances will inherit it via the prototype chain, but changing it via an instance will give that instance its own copy of it. Example:
var Foo = function() {
};
Foo.prototype.bar = 0;
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.bar, f2.bar); // 0, 0 -- both are still using the `bar` on the prototype
++f1.bar;
console.log(f1.bar, f2.bar); // 1, 0 -- f1 now has its own
Foo.prototype.bar += 2;
console.log(f1.bar, f2.bar); // 1, 2 -- f2 is still using the `bar` on the prototype
The problem with this code is that since I'm declaring the countInstances after the constructor, I'm getting an error in the constructor code itself. How to correct this??
No, the problem is that your instances have no this.prototype object. The prototype property on the function is not copied as a prototype property on instances; it's assigned to them as their prototype, which (somewhat confusingly) isn't called prototype. For a long time it didn't have a name outside the spec at all. You can access it via Object.getPrototypeOf(this) or (this will be standard for browser-based JavaScript as of the next spec) the __proto__ property.
But putting it on the prototype probably doesn't make sense. I'd just use a property on the function itself:
var Component = function(name) {
this.name = name;
this.add = function(){Component.instances++;};
this.add();
};
Component.instances = 0;
But you said you wanted to count the number of objects created by the constructor; the above counts the number of times the add method is called. To count the number of instances created by the constructor, increment it in the constructor:
var Component = function(name) {
Component.instances++;
this.name = name;
this.add = function(){/*Presumably you're doing something here*/};
this.add();
};
Component.instances = 0;
var ComponentCounter = 0;
var Component = function(name) {
this.name = name;
this.add = function(){this.prototype.countInstances++;};
this.add();
ComponentCounter++;
// or Component.counter++;
};
// or add it as a property of Component after it has been defined
// Component.counter = 0;
Variables in the prototype belong to the instance so you have to keep track of that data on a variable that is persisted between instances.
We will be able to do the same by using:
function component() {
if(component.prototype.counter) { component.prototype.counter = 0; }
component.prototype.counter++;
this.add = function(){ /*... do something here....*/ }
}
By initiating counter inside the function body, we will be able to keep the count (number of times function called).
Related
i'm new to JS and got the following problem:
Why is this not working / what is this code doing?
var Test = {};
Test.prop = "test property";
Test.Class1 = function () {
}
Test.Class1.prototype = {
m1: function() {
console.log(this.prop);
}
}
Test.Class1.m1();
My understanding of this code would be:
creating a new object called Test
adding the property prop to Test
creating a new object called Class1 in Test
adding a method m1 to Class1
calling the m1 method of Class1 in Test
In JavaScript, even the prototype property of a function is an object. Prior to creating an object whose prototype is the one you've defined, Test1.Class1.prototype is just a regular object. Basically it works the same way as the following code snippet:
var Test1 = { prototype { m1: function() {} } };
// You're trying to call an undefined function!
Test.m1();
// This is fine
Test1.prototype.m1();
In the other hand, when you use the new operator, you're creating a new object whose prototype is the one set to the constructor function. And here starts the magic:
var Test1 = function() {};
Test1.prototype = {
doStuff: function() {}
};
var object1 = new Test1();
// This works!
object1.doStuff();
When you access a property, JavaScript's runtimes inspect the object to find out if there's a function called doStuff, otherwise it looks for it on the object's prototype, otherwise it looks on the prototype of the prototype and so on...
Actually new operator is a syntactic sugar. ECMA-Script 5 introduced Object.create which makes everything more clear:
var Test1 = {
doStuff: function() {
}
};
// The first parameter of Object.create is
// the object that's going to be the prototype of
// Test1 object!
var object1 = Object.create(Test1);
// This works too!
object1.doStuff();
Probably you should check this other Q&A: How does JavaScript .prototype work?
You need to create an instance of the prototype before you're able to use its methods:
var instance = new Test.Class1();
console.log(instance.m1());
Even as such, Test.prop is not part of the instance, and will not be accessible to m1
Edit: Here's a working example:
var test = function() {
this.prop = "A property";
}
test.prototype.m1 = function() {
console.log(this.prop);
}
var instance = new test();
console.log(instance.m1());
prototype chaining only works for instances created with the new operator.
Otherwise you will have to explicitly call prototype to access the method.
let testClass = new Test.Class1();
testClass.m1();
Also since you are trying to access the prop property.
Test.Class1.prototype = {
m1: function() {
console.log(this.prop);
}
}
The call site is Test.Class1, the prop should be part of Test.Class1 and not on Test
I changed up the names of things, but this should work.
var Person = function(){
this.message = "Hello, world!";
};
Person.prototype = Object.create(Object.prototype);
Person.prototype.constructor = Person;
Person.prototype.greet = function(){
console.log(this.message);
alert(this.message);
};
var tom = new Person();
tom.greet();
I have a variable at some point of a JavaScript code. Now I would like to get the name of the function (aka scope) where that variable was declared. So for example if that variable is a field of an oject, I would like to get the name of the object's type.
Consider the following code:
function MyClass() {
this.name = "MyName";
this.age = 20;
}
var myVariable = new window.MyClass();
alert(getDeclaringScope(myVariable)) // should alert 'window'
alert(getDeclaringScope(myVariable.name)) // should alert 'MyClass
Is there any way to implement the getDeclaringScope function?
UPDATE
I wanted to use some technic like this to access to access a kind of "static" variable where meta information is stored for knockoutjs observable. A farly simplified example:
var META = {};
META["MyClass"] = {};
META["MyClass"]["MyArray"] = { ElementType: "MyOtherClass" };
function MyClass() {
this.MyArray = ko.observableArray();
}
function MyOtherClass() {
this.name = "a";
}
ko.observableArray.fn.addFromPlainObjects = function(plainItems) {
var elemType = .... here I wanted to get "MyOtherClass" from the META global variable
// create MyOtherClass and map the plain items to it... etc.
}
No.
The object has a reference to its constructor, but the constructor could be referenced from many objects, not just window in this case. It could be accessed directly with a variable (as opposed to a property):
var MyClass = window.MyClass;
var foo = new MyClass();
You can create a back-reference explicitly in your object model, as constructor functions are objects.
window.MyClass.backref = window;
Though this is most likely not what you want. I suspect you have a misunderstanding regarding what the scope of a variable is; a variable scope has nothing to do with object properties. As such, there is no notion of "declaring scope" that represents the object and object property from which a variable reference was retrieved, as you seem to conceptualize it.
You can use instanceof and constructor:
Eg.
myVariable instanceof MyClass; //true
myVariable.constructor;
// returns
function MyClass() {
this.name = "MyName";
this.age = 20;
}
Check: instanceof and constructor
Suppose I have two constructor function:
var Person = function(xx,xx,xxx,xxxxxxx) {
//Person initialization
}
var Man = function(xx,xx,xxx,xxx) {
//Man initialization
}
And I want Man extends from Person.
The following is what I thought:
Given a created Man object:
var m=new Man("xx",....);
1) when a property of m is accessed,it will search it in Man.prototype.
2) If not find, It should find it in Man.prototype.__prop__.
So what I have do is make the Man.prototype.__prop__ linked to Person.prototype.
I know this is the common way:
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
Man.prototype=inherit(Person);
But when I try this:
Man.prototype.prototype=Person.prototype.
Why it does not work?
It sounds like you actually want to link instances of Man to an instance of Person that retains any properties added in its constructor, in which case you might really want something like this:
function Person(a, b) {
this.a = a;
this.b = b;
}
function Man() {}
Man.prototype = new Person("val1", "val2");
var m = new Man();
console.log(m.a);
...which prints val1.
Additional Ramblings
The purpose of inherit is to create an object from a function whose prototype is that of the given super class (without explicitly using new), which is exactly what it does. Therefore, the following prints string:
function Person() {}
Person.prototype.test = "string";
function Man() {}
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
var t = inherit(Person);
console.log(t.test);
But you generally want to assign the returned object to another function's prototype:
Man.prototype = inherit(Person);
var m = new Man();
console.log(m.test);
...so that m.test also prints string, which means that objects created using Man are linked to Person's prototype).
Note that Man.prototype.prototype is undefined and -- this is the important part -- also meaningless. Functions have prototypes. Other objects (such as Man.prototype) do not. The prototype property is not magical in any other context. Assigning a value to a random object's prototype property doesn't do anything special. It's just another property.
Note also that the thing we returned from inherit is linked to Person by way of its prototype and has no access to any properties added to instances of Person.
How I do it (in regards to your example):
var Person = function () {
}
// Define "Person" methods
var Man = function () {
}
Man.prototype = new Person();
// Define "Man" methods
UPDATE
Regarding constructors with parameters: just found this SO question that can really help you figure it out (second answer, first part): JavaScript inheritance: when constructor has arguments.
There are quite a few generic methods to do that. I will provide three of them:
1.) Using Function object as a constructor and as a prototype object for inherited new objects. The implementation should look like as the following:
var person = {
toString : function() {
return this.firstName + ' ' + this.lastName;
}
}
function extend(constructor, obj) {
var newObj = Object.create(constructor);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
var man = extend(person,
{
sex: "male",
age: "22"
});
var name = extend(man,
{
firstName: "Simo",
lastName: "Endre"
});
name.man;
name.toString();
2.) In this case we'll use the Function object as the constructor for simulating the classical inheritance in a language like C# or Java. The prototype property of an object will be used in the role of a constructor and the the newly created object will inherit all the properties from the object prototype root. In this case the object's prototype has only one kind of augmentation role, the effective implementation is done in the function method.
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.toString = function() {
return this.firstName + ' ' + this.lastName;
}
function inherit(func) {
// passing function arguments into an array except the first one which is the function object itself
var args = Array.prototype.slice.call(arguments, 1);
// invoke the constructor passing the new Object and the rest of the arguments
var obj = Object.create(func.prototype);
func.apply(obj, args);
//return the new object
return obj;
}
var man = inherit(Person, "Simo", "Endre");
man.toString();
3.) The well known inheritance model:
function extend(o) {
function F() {}
// We'll set the newly created function prototype property to the object.
//This act as a constructor.
F.prototype = o;
// Using the `new` operator we'll get a new object whose prototype is o.
return new F();
};
Whats the difference between (via prototypes)
var Todo = {};
Todo.prototype.name = "...";
Todo.prototype.hello = function() { ... }
Vs (variables & functions "outside" object)
var Todo = {}
Todo.name = "..."
Todo.hello = function() { ... }
Or even the below : variables & functions in object
var Todo = {
name: "...",
hello = function() { ... }
}
Think it like
A property or a function declared with prototype is an instance member of Todo.
A property or a function declared without prototype is a static member of Todo.
The first one doesn't make sense as you are dealing with an object instance (({}) instanceof Object === true), it won't have a prototype property (Object does).
You may be inquiring about the difference between these two patterns...
var ObjA = function() {
this.method = function() {};
};
var ObjB = function() {};
ObjB.prototype.method = function() {};
jsFiddle.
The former will use more memory when instantiated - each object has their own method. The latter won't each have their own method, the method lives on the prototype object, which is the next in command on the prototype chain when its attempted to be accessed on the parent.
Todo.prototype is also an object, so the difference is if you declare property with prototype, then every object who created from this prototype will have the property, otherwise, the property is only for Todo the object self.
A significant difference between method #1 and #2 (which is almost identical to example #3) is on new keyword that you need to use if you extend your function via prototype, e.g.
var Todo1 = function() {};
Todo1.prototype.name = "Foobar";
var Todo2 = {name: "Foobar" }
var a = Todo1;
console.log(a.name); // no property retrieved
var b = Todo2;
console.log(b.name); // Foobar
var c = new Todo1;
console.log(c.name); // Foobar
Ok so I have been trying to figure out a way to make plain old Javascript have some sort of extension inheritance like many other OOP languages. But I have run into a specific problem, when a class extends a parent class using prototype each child of that object share variables rather than have their own new instance of the parent. For example:
TestB.prototype = new TestA();
function TestB(){ }
function TestA(){
var num = 0;
this.count = function(){
num ++;
console.log(num);
}
}
var test = new TestB();
test.count();
var test2 = new TestB();
test2.count();
So what happens is when the code is run the console looks like this:
1
2
Where as what I would prefer is for the "num" variable being inherited from the parent class to be unique to each respective instance and thus the output should be:
1
1
I assume this happens because when prototype is called it only creates a single new instance of TestA rather than one for each time TestB's constructor is called. The problem is that I have not been able to find another way to make it work?
thanks for any help (and note this is actually for a more specific use but I just wanted to create a super simple test case to illustrate the problem cleanly. I do not have the freedom to use an external library such as jQuery or prototype.js to solve the problem)
You are not supposed to define methods in the constructor but in the prototype. This saves memory
, performs better as well as allows the class to be extended cleanly.
function TestA() {
this.num = 0;
}
TestA.prototype = {
count: function() {
console.log( this.num++ );
},
constructor: TestA
};
function TestB(){
TestA.apply( this, arguments ); //Run parent constructor when instantiating a child
}
TestB.prototype = Object.create( TestA.prototype ); //Don't invoke the constructor when merely establishing inheritance
var test = new TestB();
test.count(); //0
var test2 = new TestB();
test2.count(); //0
As far as I know, prototypes only come in to play when reading a property. When you edit a property via the instance and not the prototype, the instance makes it's own property of the same name and the edited value. The prototype value stays the same.
In your example, you carried over a private variable, that is not visible from the outside. Therefore, it can't be "edited" and will carry its value through all instances of the inheriting classes.
In this sample, this makes num public so that it's editable and "patchable" at the instance level.
var test, test2;
function TestA() {
this.num = 0; //public num
this.count = function() {
this.num++;
console.log(this.num);
}
}
function TestB() {} //instances of TestB don't have properties
TestB.prototype = new TestA();
test = new TestB();
test2 = new TestB();
//monitor the instances
console.log(test);
console.log(test2);
test.count(); //these create a num property at the instance level
test2.count(); //but the prototype num remains 0
test2.count();
test2.count(); //test will have 1 and test2 will have 3
Before count operations:
Object -> TypeA -> TypeB -> test
'-> num = 0 '->num = 0 (from TypeA)
'-> count() '->count() (from TypeA)
Object -> TypeA -> TypeB -> test2
'-> num = 0 '->num = 0 (from TypeA)
'-> count() '->count() (from TypeA)
After count operations, prototype num remains 0 and the instance will have num:
Object -> TypeA -> TypeB -> test
'-> num = 0 '->num = 1 (on the instance)
'-> count() '->count() (from TypeA)
Object -> TypeA -> TypeB -> test2
'-> num = 0 '->num = 3 (on the instance)
'-> count() '->count() (from TypeA)
The moment you write to an inherited property of an instance, a new copy of the property is created for that instance.
Fore example, suppose you have:
var objB1 = new TypeB();
var objB2 = new TypeB();
where TypeB inherits the val property from TypeA.
console.log(objB1.val); // reads the inherited value of property val
console.log(objB2.val); // also reads the inherited value of property val
But the moment you write that property, such as:
objB1.val = 35; // objB1 now gets a new copy of the val property.
or
objB1.val++; // objB1 now gets a new copy of the val property.
In both the above cases, when objB1.val is written, it no longer refers to the inherited property but instead a new copy of the property val is created for instance objB1
If you want to store count, one way is to share it; for convenience you can make it a property of the constructor function of your parent class. So the count function would become:
function TestA(){
this.count = function(){
TestA.num++;
console.log(TestA.num);
}
};
TestA.num = 0;