Javascript: Instance name in a class method - javascript

<html>
<body>
<div id="output"></div>
<script>
function jExgTrend(){
}
jExgTrend.prototype.Start = function(text)
{
//this must return Instance name : "TestObj"
var InstanceName = "TestObj";
document.getElementById("output").innerHTML = ""+text+"";
}
jExgTrend.prototype.Notify = function(msg)
{
alert(msg);
}
var TestObj = new jExgTrend();
TestObj.Start("Text of the link");
</script>
</body>
</html>
How can I do something like this ? the method "Start" should return the name of the Instance of the class.
The problem is stupid I know :-(

Maybe what you really need is an id, not a name.
Providing an id is something you can easily add with a method that you can add to Object's prototype or just to the class(es) that interest you :
var idGetter = (function() {
var currentId = 0;
return function() {
// 1. replace 'id' with a readonly property
// that will return id for this object
var thisId = currentId ;
Object.defineProperty( this, 'id',
{ get : function () { return thisId; } } ) ;
// 2. for the first run of id, return object id
return currentId++;
}
}());
Object.defineProperty( Object.prototype, 'id', { get : idGetter } );
small example of use :
var someObject = {};
console.log(someObject.id); // outputs 0
var someObject2 = {};
console.log(someObject2.id); // outputs 1
Notice that Object.defineProperty defaults to a non-enumerable property, so your objects won't get 'polluted' by this property (when using for..in for instance).

You can't. You can specify a name at instantiation though:
function JExgTrend(name){ this.name = name || 'no name specified'; }
JExgTrend.prototype.Start = function () {
alert(this.name);
}
var testObj = new JExgTrend('testObj');
var otherTestObj = new JExgTrend('otherTestObj');
var anon = new JExgTrend;
testObj.Start(); //=> testObj
otherTestObj.Start(); //=> otherTestObj
anon.Start(); //=> no name specified
A somewhat exotic alternative: you could program the constructor like this:
function JExgTrend(name,scope) {
name = name || ( Math.floor( 10000+Math.random()*100000000000) ).toString(16);
if (!(this instanceof JExgTrend)) {
return new JExgTrend(name,scope);
}
this.name = name;
if (!JExgTrend.prototype.myname) {
JExgTrend.prototype.myname = function(){ console.log(this.name); };
}
return (scope || window)[this.name] = this;
}
And then assign objects like this:
jExgTrend.call(null, 'testObj');
testObj.myname(); //=> testObj
Try fiddling around # this jsFiddle

Related

how to right choose javascript pattern

i create 2 objects:
var Documentos = new QuadForm();
var Cadastro = new QuadForm();
And initialize this objects with lot of options
Cadastro.initForm(options);
Documentos.initForm(options2);
then i try to separate the data managed by each object with getName method but after the second object, myObjectName variable is overrided.
var QuadForm;
QuadForm = function () {
this.getName = function () {
// search through the global object for a name that resolves to this object
for (var name in window)
if (window[name] == this) {
window[name] = this;
window[window[name]] = window[name];
myObjectName= name;
break;
}
},
this.initForm = function (parms) {
this.getName()
$.extend(this, parms);
if (window.myState) {
delete window.myState;
}
this.containerId = parms.formId;
this.getForm(parms);
this.workflowLabels('hide');
then i use window[myObjectName].totalRecords but as it changes to the latest object name off course cannot access data.
How can i manage this.
It's not a big problem to manage several instances, but your approach is impossible, cause you can't really find all possible instances and your code does definitely not what you expected to do.
For example you can define a variable on the constructor-object which holds all instances, and than you can use it in some cases:
var QuadForm = function (name) {
this.name = name;
QuadForm.instances.push(this);
this.showAllOtherInstances = function () {
QuadForm.instances.forEach(function (instance) {
if (instance !== this) {
console.log('name: ' + instance.name);
}
}.bind(this));
}
}
QuadForm.instances = [];
var foo = new QuadForm('foo');
var anotherFoo = new QuadForm('foo');
var bar = new QuadForm('bar');
var aThirdFoo = new QuadForm('foo');
foo.showAllOtherInstances();
/*
* Output:
*
* name: foo
* name: bar
* name: foo
*/

Append to constructor

This object constructor is the definition of a person:
var Person = function( age, name ){
this.age = age;
this.namge = name;
};
this is a line of code that will give the prototype of Person an array called "active"
Person.prototype.active = [];
The reason I am adding this to the prototype, is so that there is only one active array that every person, meaning Jim in this case: var Jim = new Person() ), SHARES the exact same active array.
From that point I want to add in every newly created person into the active array.
This is how I would do it:
var Jim = new Person(age, name);
Jim.active.push( Jim );
var Tim = new Person(age, name);
Tim.active.push( Tim );
What I expected from this, is for Tim.active[0] to be Jim and for
Jim.active[1] to be Tim.
The problem is, is that I want the active.push[ self id ] to be called
when a new Person is created, without the second line doing it. My solution for this would be modifying the Person constructor too look like this:
var Person = function( age, name ){
this.age = age;
this.namge = name;
this.active.push( this );// The constructor now adds itself to the array during initiation
};
As you can see, it puhes itself into the active array. The problem is that I want my object to do exactly this, but I want the constructor to begin like the first one I provided with this.active.push appended later in the code.
How do I expect this to be solved? My thoughts were that since the active array could be initiated anytime inside the program, that the functions constructor could somehow append this.active.push() to the end of it at right after Person.prototype.active = [] is executed.
Something that may look like:
Person.prototype.active = [];
Person.prototype.append( function(){this.active.push(this)} );
The second line would morph the first object constructor to look like the second one.
Not sure why you want this approach, perhaps it can be refactored? Probably better to have some sort of PersonMediator "class" in my opinion. But, if you want to have the prototype include an active array that has conditions, then attach some way to manage those conditions to the Person object.
var Person = function( age, name ){
this.age = age;
this.namge = name;
//checks for activation flag
this.ready();
};
Person.prototype.active = [];
Person.activate = function(){ Person.prototype.activate = true; };
Person.deactivate = function(){ Person.prototype.activate = false; };
Person.prototype.activate = false;
Person.prototype.ready = function(){
//depending on activate flag, appends to active array
if( this.activate ) this.append();
};
Person.prototype.append = function(){
//array append
this.active.push(this);
};
var Jim = new Person(10,'Jim');//not added, default flag false
//activate flag for appending
Person.activate();
var Tim = new Person(20,'Tim');//now added to the active array
console.log(Jim.active);//shows only Tim
console.log(Tim.active);//shows only Tim
That said, this is how I would manage this.
var Person = function( age, name ){
this.age = age;
this.namge = name;
};
var PersonMediator = function(){
this.alive = [];
this.removed = [];
};
PersonMediator.prototype.create = function(age, name){
var person = new Person(age,name);
this.alive.push(person);
return person;
};
PersonMediator.prototype.remove = function(person){
for(var i = 0; i < this.alive.length; i++){
if( this.alive[i] === person ){
this.alive.splice(i,1);
}
}
this.removed.push(person);
};
var pm = new PersonMediator();
var Jim = pm.create(10,'Jim');
var Tim = pm.create(20,'Tim');
console.log(pm.alive);
If you simply want to store the instantiated objects to an array, you can use an inheritance pattern like so:
var myArray = [];
function SuperClass() {
myArray.push(this);
};
function Block(name) {
this.name = name;
SuperClass.apply(this, arguments);
};
function Player(name) {
this.name = name;
SuperClass.apply(this, arguments);
};
var baller = new Player('Jim');
var blocker = new Block('Joe');
console.log(myArray); // [Player, Block]
Every time a new instance of Player or Block is instantiated, it will add it to the array.
Another pattern you may consider is having a set prototype object that you can add your prototypical methods and shared data to, and then assigning it as the prototype in your constructor function
var personPrototype = {
alive: []
}
var blockPrototype = {
alive: []
}
var Person = function(x, y){
//this creates a new object with the prototype of our personPrototype object
var o = Object.create(personPrototype);
//then we can configure / add instance-specific attributes and return the object
o.x = x;
o.y = y;
return o;
}
var Block = function(x, y){
var o = Object.create(blockPrototype);
o.x = x;
o.y = y;
return o;
}
var me = new Person(1, 2);
var square = new Block(10, 20);
// > []
me.alive
By using Object.create to create a dummy object we can effectively assign it a proper prototype. Then we can add whatever instance attributes we'd like, and return that object. This means that the personPrototype will be a proper prototype. Each instance can use instance.alive or instance.alive.push directly, since it automatically walks up the prototype chains
It also allows you to easily add any new data to the prototype of all your instances. You don't need to iterate through each instance and add prototypical methods. You can just add the method to the prototype to start and it will be accessible on all instances by default.
I find the whole approach - trying to track/store [Person] instances - questionable.
But if I was in the position of being told to do so, I'd go for an approach that is build upon a
factory module. Thus being at least able of assuring "read only access" to the list of all instances
that ever got created by the factory.
A possible implementation than might look similar to the following example:
var Person = (function (global, Object, Array, Math) {
var
array_from = ((typeof Array.from == "function") && Array.from) || (function (array_prototype_slice) {
return function (listType) {
return array_prototype_slice.call(listType);
};
}(Array.prototype.slice)),
personModule = {},
personList = [],
Person = function (config) { // constructor.
var person = this;
person.name = config.name;
person.age = config.age;
person.constructor = Object;
return person;
},
isPerson = function (type) {
return (type instanceof Person);
},
createPerson = function (age, name) { // factory.
/*
- sanitizing/validation of arguments etc. should be done right here.
- create instances only if all the conditions are fulfilled.
*/
var person = new Person({
name: name,
age : age
});
personList.push(person);
return person;
}/*,
removePerson = function (type) {
if (isPerson(type)) {
// remove person from the internal list.
}
}*/
;
//personModule.remove = removePerson;
personModule.create = createPerson;
personModule.isPerson = isPerson;
personModule.all = function () { // expose internal instance list.
return array_from(personList);
};
personModule.all.size = function () {
return personList.length;
};
(function () { // make [personModule.all] enumerable.
var
parse_float = global.parseFloat,
math_floor = Math.floor
;
this.first = function () {
return (this()[0]);
};
this.last = function () {
var list;
return ((list = this())[list.length - 1]);
};
this.item = function (idx) {
return (this()[math_floor(parse_float(idx, 10))]);
};
}).call(personModule.all);
return personModule;
}((window || this), Object, Array, Math));
var Jim = Person.create("Jim", 21);
var Tim = Person.create("Tim", 19);
console.log("Jim", Jim);
console.log("Tim", Tim);
console.log("Person.isPerson(Jim) ? ", Person.isPerson(Jim));
console.log("Person.isPerson(Tim) ? ", Person.isPerson(Tim));
console.log("Person.isPerson({name: 'Tim', age: 21}) ? ", Person.isPerson({name: 'Tim', age: 21}));
console.log("Person.all.size() : ", Person.all.size());
console.log("Person.all() : ", Person.all());
console.log("Person.all.first() : ", Person.all.first());
console.log("Person.all.last() : ", Person.all.last());
console.log("(Person.all()[1] === Person.all.item(1)) ? ", (Person.all()[1] === Person.all.item(1)));
console.log("(Person.all.first() === Person.all.item(0)) ? ", (Person.all.first() === Person.all.item(0)));

Creating behaviour that is both like a JavaScript object literal as a function

I'd like to be able to do the following:
person('male');
person.age(34);
As you can see, I want the person object to be both a function as an object. What I mean is that doing so:
function person(gender){
this.gender = gender || 'unknown';
}
excludes me from doing so:
person.gender; // undefined
unless I create a new object from the person function, like so:
var me = new person();
me.gender; // 'unknown'
which I do not want, as I still want to be able to set other properties, like so:
person.age = 34;
Is this even possible? Of am I trying to accomplish the impossible?
To clarify: I don't want to need to create instances. The key is that I just want to be able to both call the function person as call a function.property().
EDIT: Perhaps I've confused many (including myself) by using a wrong example. A simpler question would be: How would I be able to call a function and a 'property' of that function, like so:
car();
car.start();
both at the same time without the need to create an instance of car?
We might be able to give a better answer if you would explain the motivation behind what you want to do. However, yes, what you describe is possible. In JavaScript, functions are just another type of object. That means that you could define a function, then set properties on it like so:
var person = function () {
return "Hi, I am a person!";
};
person.species = "human";
person.foo = 42;
console.log( person() ); // prints: Hi, I am a person!
console.log( person.species ): // prints: human
console.log( person.foo ); // prints: 42
Or working from your second example:
var car = function () {
return {
model: "Focus",
make: "Ford",
year: 2010
};
};
car.start = function () {
return "Vroom!";
};
console.log ( car.make ); // prints: Ford
console.log ( car.start() ); // prints Vroom!
By the way, this is not the same as a function that returns an object. That might look like this:
var person = function () {
return {
species: "human",
name: "Bob",
age: 27
};
};
var bob = person();
bob.occupation = "cubicle drone";
console.log( bob.name ); // prints: Bob
console.log( bob.occupation ); // prints: cubicle drone
console.log( person.occupation ); // prints: undefined
console.log( bob == person ); // prints: false
Variables bob and person both hold objects, but not the same object, not even the same type of object.
Instead of using this inside your function, which refers to the Object instance created when running this function as a constructor by invoking it with the new operator you can use arguments.callee to refer to the function itself
function person(gender){
arguments.callee.gender = gender || 'unknown';
}
If you want to ensure that a function is always used as a constructor even if invoked without the new operator, you can do it by implicitly invoking it.
function person(gender){
if(!(this instanceof person)){ return new person(gender); }
this.gender = gender || 'unknown';
}
In all other regards functions can do anything regular objects can, that's why they are often described as "first class objects".
You can simply assign them properties like objects, or methods like
function car(){
}
car.start = function(){
}
You can also let them inherit methods from a function using the __proto__ property.
function bird(){}
function platypus(){}
bird.layEggs = function(){};
platypus.__proto__ = bird;
platypus.layEggs() // now you know
a small example using the instanceof way that #Winchestro is using
on jsfiddle:http://jsfiddle.net/47EEr/
'use strict';
function person(gender, age, name) {
if (!(this instanceof person)) {
return new person(gender, age, name);
}
var props = { gender: '', age: 0, name: '' }, fnCreateProp = function(prop, value) {
Object.defineProperty(this, prop, {
get: function() {
return props[prop];
},
set: function(val) {
console.log('setting prop ' + prop + ' to ' + val);
props[prop] = val;
}
});
}.bind(this);
for (var prop in props) {
if (!props.hasOwnProperty(prop)) {
continue;
}
fnCreateProp(prop, props[prop]);
}
this.gender = gender;
this.age = age;
this.name = name;
this.toString = function(element) {
var str = '[Person=(';
for (var prop in props) {
if (!props.hasOwnProperty(prop)) {
continue;
}
if (str.indexOf('(') !== str.length-1) {
str += ',';
}
str += prop +': ' + props[prop];
}
str += ')]';
if (typeof element !== 'undefined') {
var el = document.getElementById(element);
if (el) {
el.innerHTML = str;
}
}
return str;
};
this.birthday = function() {
this.age++;
};
}
var p1 = person('male', 33, 'male 1');
var p2 = new person();
p2.age = 32; p2.gender = 'female'; p2.name = 'female 1';
p1.toString('person1');
p2.toString('person2');
p2.birthday();
p2.toString('person2birthday');
You can also do:
function person(gender){
return {
gender: gender || 'unknown'
};
}
var p = person('male');
p.age = 34;
p.name = 'John';
etc...
No "new" is used and you can still re-use the person function.
Your edit:
EDIT: Perhaps I've confused many (including myself) by using a wrong example. A simpler question would be: How would I be able to
call a function and a 'property' of that function, like so:
car();
car.start();
both at the same time without the need to create an instance of car?
Is this what you are looking for?
function car() {
console.log("car called");
car.start = function() {
console.log("car.start called");
}
}
car();
car.start();
/**** output:****
car called
car.start called
*/

Returning private object property by name (string) in Javascript

I have worked out a method to access an objects private properties by creating a method that returns those properties. However I would like to create a single function that can return any object property based on the string argument passed.
Here is an example of what I am trying to do:
function MyObj() {
var myProp = 10;
this.getProp = function( propName ) {
return( propName ); // THIS IS WHERE I AM STUCK
};
}
MyObj.prototype.getMyProp = function() {
return this.getProp( 'myProp' );
};
var myObj = new MyObj();
console.log( myObj.getMyProp() );
As you can see from this example the string "myProp" is returned not the variable. I can't use this[propName] as I'm not in the right scope and I can't use the that/self technique to access the scope.
How do return an object property using a string?
One simple solution would be to wrap your private variables in an object like this:
function MyObj() {
var privateVars = {
myProp: 10
};
this.getProp = function( propName ) {
return privateVars[propName];
};
}
MyObj.prototype.getMyProp = function() {
return this.getProp( 'myProp' );
};
var myObj = new MyObj();
console.log( myObj.getMyProp() ); // 10
Update: it appears that eval will work in this case, too, but I wouldn't recommend it:
function MyObj() {
var myProp = 10;
this.getProp = function( propName ) {
return eval(propName);
};
}
MyObj.prototype.getMyProp = function() {
return this.getProp( 'myProp' );
};
var myObj = new MyObj();
console.log( myObj.getMyProp() ); // 10

Static/shared property and method in JavaScript

I'm trying to have a 'class' in JS which tracks how many instances of itself have been instantiated. I am attempting to do so like this...
var myNamespace = {};
myNamespace.myClass = function () {
//fails here as .getNetInstanceNo() not recognised...
var instanceNumber = myNamespace.myClass.getNextInstanceNo();
return {
instanceNo : function() { return instanceNumber; }
}
};
myNamespace.myClass.InstanceNo = 0; //static property?
//should the class itself have this method added to it...
myNamespace.myClass.prototype.getNextInstanceNo = function () { //static method?
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo() );
However this fails as the getNextInstanceNo function is not recognised. Even though I think I'm adding it through the myClass.prototype.
What am I doing wrong?
prototype is an object from which other objects inherit properties, as in when you create an instance of an object and that object doesn't have a property/method, when called, the prototype of the class in which the object belongs to is searched for that property/method, here's a simple example:
function Animal(){};
Animal.prototype.Breathe = true;
var kitty= new Animal();
kitty.Breathe; // true (the prototype of kitty breathes)
var deadCat = new Animal();
deadCat.Breathe = false;
deadCat.Breathe; // false (the deadCat itself doesn't breath, even though the prototype does have breath
As you said yourself, you don't need to define getNextInstanceNo on prototype, since that's not how static methods are defined on JavaScript, leave it right right there on the class itself, instead you can define the instanceNo method on prototype, here's how:
var myNamespace = {};
myNamespace.myClass = function () {
this.instanceNumber = myNamespace.myClass.getNextInstanceNo();
};
myNamespace.myClass.prototype.instanceNo = function () {
return this.instanceNumber;
};
myNamespace.myClass.InstanceNo = 0;
myNamespace.myClass.getNextInstanceNo = function () {
return myNamespace.myClass.InstanceNo++;
};
var class1 = new myNamespace.myClass();
alert('class 1 has instance of ' + class1.instanceNo());

Categories

Resources