Javascript prototype and issues accessing class - javascript

Family = function(name) {
this._Name = name;
}
Family.prototype = {
getName: function() {
return this._Name;
},
People: function(num) {
this._Number = num;
}
}
Family.People.prototype = {
clearNumber: function() {
this._Number = 0;
}
}
People is a nested class. Its parent class is Family.
I get the error that Family.People is undefined. Could someone correct the code above?

Working code
// function doesn't need "new" operator
var Family = function(name) { this._Name = name; };
Family.prototype = {
getName: function() { return this._Name; }, // missing comma
People: function(num) {
this._Number = num;
}
};
// work with prototypes
Family.prototype.People.prototype = {
clearNumber: function() { this._Number = 0; }
};
This will work. But you have to be aware, that when you call:
var f = new Family("Doe");
f.People is just an object constructor, and not an instance of some other object. You will have to instantiate it as well like:
f.members = new f.People(3);
Sou you have a constructor within your instance which is rather confusing.
A better approach
So it would probably be better if you'd write your prototypes this way:
var Family = function(name) {
this._Name = name;
this.getName = function() { return this._Name; };
};
Family.People = function(num) {
this._Number = num;
this.clearNumber = function() { this._Number = 0; };
};
This actually makes a class within a class (and not within instances). So upper lines would be called this way:
var f = new Family("Doe");
f.members = new Family.People(3);
Drill down of f instance would look like:
f
_Name
getName()
members
_Number
clearNumber()
Private variables
var Family = function(name) {
var _name = name;
this.getName = function() { return _name; };
};
Family.People = function(num) {
var _num = num;
this.getNumber = function() { return _num; }
this.clearNumber = function() { _num = 0; };
};
This way we make variables private and only accessible within so they can't be manipulated outside. You must always use functions to manipulate them. This makes it more robust especially when there are certain business rules related to variable values.
var f = new Family("Doe");
f._name; // this is undefined because "_name" is private closure variable
Drill down of f instance would now look more like a class object instance:
f
getName()
members
getNumber()
clearNumber()

Notice that you are assigning to Family.prototype.People then trying to access Family.People.
Family is not an instance of Family thus it does not have the properties of that class - Family is an instance of Function thus you are trying to access Function.prototype.People in that 3rd statement. (this is a bit of a simplification)
i.e. what you want to be doing is
Family.prototype.People.prototype = {
clearNumber:function(){this._Number = 0;}
}
You are also missing a comma before people, but I assume this is a typo...

You should declare the People constructor as a key in the Family object:
Family.People = function(num) {
this._Number = num;
}
The Family prototype will be in the prototype chain for new objects of type Family; not a part of Family itself.

Related

Javascript context in inner class object

Prior to using ES6 we could instantiate a "class" like so...
var Animal = function(){}
and then...
var dog = new Animal()
the context within the "class" will be the class (instance) itself
var Animal = function( name ){
this.name = name;
this.getName = function(){
// the context here (this) is the class (Animal)
return this.name; // works well
}
}
The question is, if I wouldn't want to pollute the root scope and use sub-objects, for various uses, then the context would become the object in which the function is being kept
var Animal = function( name ){
this.utilities = {
this.getName : function(){
// the context here is the 'utilities' object so...
return this.name // wouldn't work
}
}
}
of course we could always use something in the form of
dog.utilities.getName.call(dog)
but this would be kind of long and uncomfortable...
is there a way to create the 'utilities' object and apply the context to all of its functions to point back to the root scope? without having to use call and apply every time? (an answer without using ES6 would be great...)
One way to ensure that this is what you want it to be in the various utilities functions is to use arrow functions for them, since arrow functions close over the this where they're defined:
class Animal {
constructor(name) {
this.name = name;
this.utilities = {
getName: () => { // This is an arrow function
return this.name; //
} //
};
}
}
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
This is basically the ES2015+ version of the old var t = this; solution:
function Animal(name) {
var t = this;
this.name = name;
this.utilities = {
getName() {
return t.name;
}
};
}
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
In both cases, this means that you're creating new function objects for each individual instance of Animal (the code will be shared between those objects, but the objects are distinct). That's fine unless there are going to be a lot of Animal instances.
Alternately, you could have a helper that you pass the instance to:
const Animal = (function() {
class Utilities {
constructor(animal) {
this.a = animal;
}
getName() {
return this.a.name;
}
}
class Animal {
constructor(name) {
this.name = name;
this.utilities = new Utilities(this);
}
}
return Animal;
})();
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
or
var Animal = (function() {
function Utilities(animal) {
this.a = animal;
}
Utilities.prototype.getName = function getName() {
return this.a.name;
};
return function Animal(name) {
this.name = name;
this.utilities = new Utilities(this);
}
})();
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
...which lets utilities reuse its function objects via Utilities.prototype.
You could probably use the following:
var utilities = function (context) {
return {
getName: function () {
console.log(context.name)
}
}
}
var Animal = function( name ){
this.name = name
this.utilities = utilities.call(null, this)
}
var dog = new Animal('dog')
dog.utilities.getName()
But, if you are okay doing this: dog.getName() instead of dog.utilities.getName() then you might have a cleaner solution (IMO) as follows:
var Animal = function( name ){
this.name = name
}
var utilities = {
getName: function () {
console.log(this.name)
}
};
Object.assign(Animal.prototype, utilities)
var dog = new Animal('dog')
dog.getName()
Let me know if that works. Thanks.
NEW ANSWER:
var UTILITIES = {
getName: function () {
console.log(this.self.name)
}
}
var Animal = function (name) {
this.name = name
this.utilities = Object.create(UTILITIES, {
self: {
value: this
}
})
}
var dog = new Animal('dog')
dog.utilities.getName()
Variation includes the use of a 'self' attribute which points to the instance of interest. Now, this could look more intuitive.
You can use getter methods. I find them very useful for cases where I need formatted value. This way, the utilities/ logic is only known to this class and is not exposed outside.
function Person(fname, lname) {
var _fname = fname;
var _lname = lname;
Object.defineProperty(this, 'fullName', {
get: function(){
return _fname + ' ' + _lname
}
});
Object.defineProperty(this, 'firstName', {
get: function(){
return _fname
},
set: function(value) {
_fname = value;
}
});
Object.defineProperty(this, 'lastName', {
get: function(){
return _lname
},
set: function(value) {
_lname = value;
}
});
}
var person = new Person('hello', 'world');
console.log(person.fullName);
person.firstName = 'Hello';
console.log(person.fullName);
person.lastName = 'World'
console.log(person.fullName);

How can I make privileged JS methods?

I want to be able to call sub-functions that work with private data. Currently I have this:
var myFunction4 = function() {
this.secret1 = 0;
this.secret2 = 0;
var that = this;
this.iterate1 = function(){
return that.secret1++;
}
this.iterate2 = function(){
return that.secret2++;
}
this.addSecrets = function(){
return that.secret1 + that.secret2;
}
return {
iterate1: this.iterate1,
iterate2: this.iterate2,
addSecrets: this.addSecrets,
}
};
The bad thing about this is that to call one of the methods, I have to do:
myFunction4().iterate1();
Which executes myFunction4() every single time I want to access a method. Not only is this inefficient, but it resets secret1 each time so I can't iterate it. I've tried using the new operator, but that exposes secret1 and secret2, and it messes up the ability to nest functions deeply.
var myFunction3 = function() {
this.secret1 = 0;
this.secret2 = 0;
this.iterate1 = function(){
return this.secret1++;
}
this.iterate2 = function(){
return this.secret2++;
}
this.addSecrets = function(){
return this.secret1 + this.secret2;
}
};
var f3 = new myFunction3();
f3.secret1; // exposes the secret!
See the console logs at the bottom of this JSFiddle for more examples.
How can I have a function with both private and public vars/methods which retain their values and don't need to be called multiple times?
While the other answers are absolutely fine and correct, there is one more issue to consider when emulating OOP behaviour in javascript.
The function execution context issue will bite us hard when we will try to use a public method as a e.g. async. callback.
The magical this will point to a different object then we expect in the OOP world.
Of course there are ways to bind the context but why to worry about this after we define the 'class' in a non OOP js ;)
Here is a simple solution to this: Do not use this. Let the closure refactor this out ;)
var myFunction4 = function() {
// we could inherit here from another 'class' (object)
// by replacing `this` with e.g. `new SuperClass()`
var that = this;
// 'private' variables
var secret1 = 0;
var secret2 = 0;
// 'public' variables
that.somePublicVar = 4;
// 'private' methods
var somePrivateMethod = function(){
secret2 = 77;
that.somePublicVar = 77;
}
// 'public' methods
that.iterate1 = function(){
return secret1++;
}
that.iterate2 = function(){
return secret2++;
}
that.addSecrets = function(){
return secret1 + secret2;
}
return that;
};
var f = new myFunction4();
console.log( f.iterate1() ); // 0
console.log( f.iterate1() ); // 1
console.log( f.secret1 ); //undefined
console.log( f.somePublicVar ); //4
Try that (closures power!):
var myFunction3 = function() {
var secret1 = 0;
var secret2 = 0;
this.iterate1 = function(){
return secret1++;
}
this.iterate2 = function(){
return secret2++;
}
this.addSecrets = function(){
return secret1 + secret2;
}
};
var f3 = new myFunction3();
now only the methods are exposeds
Edited version:
If you don't wanna execute the main function every time you call sub-method, you can change a bit your approach and use the power of IIFE (immediately-invoked function expression)
var myFunction4 = (function() {
var secret1 = 0;
var secret2 = 0;
var iterate1 = function(){
return secret1++;
}
var iterate2 = function(){
return secret2++;
}
var addSecrets = function(){
return secret1 + secret2;
}
return {
iterate1: iterate1,
iterate2: iterate2,
addSecrets: addSecrets
}
}());
Then you can use this:
myFunction4.iterate1();
myFunction4.iterate2();
myFunction4.addSecrets();
Hope this helps you
I generally only use the factory pattern to create objects unless I absolutely need to have the performance benefits of prototypical inheritance.
Using the factory pattern also means you don't have to deal with the ever changing value of this in different contexts.
var factory = function() {
// internal private state
var state = {
secret1: 0,
secret2: 0
}
function iterate1(){
return state.secret1++;
}
function iterate2(){
return state.secret2++;
}
function addSecrets(){
return state.secret1 + state.secret2;
}
function __privateMethod() {
// this is private because it's not on the returned object
}
// this is the public api
return {
iterate1,
iterate2,
addSecrets
}
}
// create a secret module
var secret = factory()
console.log(
secret.iterate1(), // 0
secret.iterate2(), // 0
secret.addSecrets(), // 2
secret.secret1, // undefined
secret.secret2 // undefined
)
// you can even create more with the same factory
var secret2 = factory()
Why don't you try Revealing Module Pattern
var myFunction4 = function() {
var secret1 = 0,
secret2 = 0,
iterate1 = function(){
return secret1++;
},
iterate2 = function(){
return secret2++;
},
addSecrets = function(){
return secret1 + secret2;
};
// public functions and properties
return {
iterate1: iterate1,
iterate2: iterate2,
addSecrets: addSecrets,
}
}();
myFunction4.iterate1(); // is available
myFunction4.secret2; // is private and not available outside of myFunction4
Hope it helps
A basic pattern:
var myFunction = function() {
var that = this;
var secret1 = 0;
var secret2 = 0; // private
this.public1 = 0; // public
this.iterate1 = function(){
return secret1++;
}
this.iterate2 = function(){
return secret2++;
}
this.addSecrets = function() { // public
return privateMethod();
}
var privateMethod = function() { // private
return secret1 + secret2;
}
return this; // return function itself!
};
var myFn = new myFunction();
myFn.public1 // 0
myFn.secret1 // undefined
myFn.addSecrets();
I recommend you to read the excellent Learning JavaScript Design Patterns by Addy Osmani.
What I understand from your explanation as per your second snippet is that you need a sharedPrivate among the instantiated objects. You can not do this with classical object creation patterns like constructor, factory or module. This is possible by taking a private variable under closure in the prototype of the constructor so that it doesn't get reset each time an object is created and at the meantime the instantiated objects are provided with necessary methods to access, modify and share it privately.
function SharedPrivate(){
var secret = 0;
this.constructor.prototype.getSecret = function(){return secret}
this.constructor.prototype.setSecret = function(v){ secret = v;}
this.constructor.prototype.incrementSecret = function(){secret++}
}
var o1 = new SharedPrivate();
var o2 = new SharedPrivate();
console.log(o1.getSecret()); // 0
console.log(o2.getSecret()); // 0
o1.setSecret(7);
console.log(o1.getSecret()); // 7
console.log(o2.getSecret()); // 7
o2.incrementSecret()
console.log(o1.getSecret()); // 8
And another method of getting a similar result would be
function SharedPrivate(){
var secret = 0;
return {getS : function(){return secret},
setS : function(v){secret = v},
incS : function(){secret++}
};
}
sharedProto = SharedPrivate(); // secret is now under closure to be shared
var o1 = Object.create(sharedProto); // sharedProto becomes o1.__proto__
var o2 = Object.create(sharedProto); // sharedProto becomes o2.__proto__
o1.setS(7); // o1 sets secret to 7
console.log(o2.getS()); // when o2 access it secret is still 7
o2.incS(); // o2 increments the secret
console.log(o1.getS()); // o1 can access the incremented value

Declaring private static member variable in JavaScript

I am stuck with a design pattern in JavaScript where I would like to create a private static member variable for keeping object count. Something along these lines:
var person = function(name){
//How to persist this value across multiple calls avoiding Globals
var _personCount = _personCount || 0;
_personCount++;
var _name = name;
getPerson = function(){
return "Person is: " + _name;
}
};
person("foo");//_personCount should be 1 after this call
person("bar");//_personCount should be 2 after this call
The idea is something to similar to private static variables, accessible only to the class's internal variables
You can use the revealing module pattern:
var something = (function() {
var myThing = 0;
return {
doSomething: function() {
myThing++;
}
};
})();
something.doSomething(); // myThing is now 1
The variable is within what's called an IIFE (immediately invoked function expression) will remain throughout the lifecycle of the program.
If you're going to instantiate the module more than once in different places, you'll need to also create a singleton.
If you want the variable to be global to all the persons, you need to define them within the scope of a containing function. This can be an IIFE, since it only need to run once.
var person = (function() {
var _personCount = _perconCount || 0;
return function(name) {
_personCount++;
var _name = name;
getPerson = function() {
return "Person is: " + _name;
};
};
})();
You must create the private static variable in the closure context.
var person = (function() {
//private variable
var _personCount = 1;
return function(name) {
this.name = name;
this.id = _personCount++;
}
}());
var foo = new person('foo');
console.log(foo.id + ' ' + foo.name);//1 foo
var boo = new person('boo');
console.log(boo.id + ' ' + boo.name);//2 boo
Here the enclosing anonymous function can never be called again. It gets executed while JS engine parses your code, and creates _personCount variable which can be accessed only by inner function function(name) making it like private static.
I think that this could help you!
note: the prototype property for having instance method!
note: count, instead, is static!
var Person = (function() {
var counter = 0;
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
counter += 1;
return this.name;
};
Person.count = function() { return counter; };
return Person;
})();
var superman = new Person('SuperMan');
var batman = new Person('BatMan');
var el = function() { return window.document.getElementById('counter'); }
function p1() {
var name = superman.getName();
el().innerText = name + ' - ' + Person.count();
}
function p2() {
var name = batman.getName();
el().innerText = name + ' - ' + Person.count();
}
<h1 id="counter">0</h1>
<button onclick="p1()">Person1</button>
<button onclick="p2()">Person2</button>

Javascript call prototype function from function inside constructor

I searched for this issue for quite a long time. Din't find any answer to satisfy my question. What I am trying is:
function myClass() {
function privateFunction () {
publicFunction(); //Error
}
}
myClass.prototype.publicFunction = function() {
this.variable = 1;
}
myClass.prototype.publicFunction2= function() {
return this.variable;
}
This is giving me error. I am not getting what the real problem is:
What I tried:
this.publicFunction();
Then:
myClass.publicFunction();
Then:
myClass.prototype.publicFunction();
This works but it overrides for each object. Acts as if it is static across different JS objects.
You haven't declared the prototype functions correctly. You are also missing the this keyword when calling the function publicFunction.
The private function (privateFunction) is not a member of the class, so if you want to call it as a function, you have to specify the context for it.
function myClass() {
function privateFunction () {
this.publicFunction();
}
privateFunction.call(this);
document.write(this.publicFunction2()); // show value in Stackoverflow snippet
}
myClass.prototype.publicFunction = function() {
this.variable = 1;
}
myClass.prototype.publicFunction2 = function() {
return this.variable;
}
var myClassPrototype = new myClass();
Wouldn't a closure be enough?
First, I'd rename myClass to MyClass by convention
function MyClass() {
var myInstance = this;
function privateFunction () {
// closure
myInstance.publicFunction();
}
}
MyClass.prototype.publicFunction = function() {
this.variable = 1;
}
MyClass.prototype.publicFunction2= function() {
return this.variable;
}
Now you should be able to instanciate it this way
var myInstance = new MyClass();
Now you can see that privateFunction is never called, and it woud be a bit redundant to call it, but I just tried to show how to technically achieve it.
Try this:
function myClass() {
function privateFunction(obj) {
obj.privilegedFunction1();
};
this.privilegedFunction1 = function () {
this.variable = 1;
};
this.privilegedFunction2 = function () {
privateFunction(this);
};
}
myClass.prototype.publicFunction2 = function () {
return this.variable;
}
var test = new myClass();
test.privilegedFunction2();
console.log(test.publicFunction2());
And this:
function myClass() {
function privateFunction(obj) {
obj.publicFunction1();
};
this.privilegedFunction2 = function () {
privateFunction(this);
};
}
myClass.prototype.publicFunction1 = function () {
this.variable = 1;
}
myClass.prototype.publicFunction2 = function () {
return this.variable;
}
var test = new myClass();
test.privilegedFunction2();
console.log(test.publicFunction2());
You may want to read some about public vs private vs privileged members in Javascript. Like this article: http://javascript.crockford.com/private.html
Key points:
Public (prototype) members have no access to private.
Privileged (this) members have access to private.
Private function may access privileged and public members through the passed context parameter.
You aren't accessing it because it's inside a private function.
Try it like this:
function myClass() {
function privateFunction () {
}
this.publicFunction = function() {
alert('ok')
}
}
then if you do
var obj = new myClass()
obj.publicFunction()
you can see the alert
In order to inherit the class you will need some other things. Here is a complete example.
Now here is the relevant js code. Put it in a file to test it:
function Operators() {
//mandatory
var self = this
//private
var IPT_X = '#x'
var IPT_Y = '#y'
//public
this.x = 0
this.y = 0
this.showOperators = function() {
//use of a private property (IPT_X) and a public property (this.x)
$(IPT_X).val(this.x)
$(IPT_Y).val(this.y)
}
this.clean = function() {
this.x = 0
this.y = 0
// call to a local public method
this.showOperators()
}
this.updateOperators = function(_x, _y) {
// use of a public property when call from
// derived class method is necessary
self.x = _x
self.y = _y
}
}
function Randomizer() {
// mandatory for derived classes
Operators.call(this)
// mandatory for overloaded methods with call to the inherited method
var parentUpdateOperators = this.updateOperators
var self = this
// private
function getRandomNumber() {
return Math.round(Math.random() * 1000)
}
// public
this.updateOperators = function(_x, _y) {
// call to inherited method of superior class
parentUpdateOperators(_x, _y)
// call to method of superior class
self.showOperators()
}
this.populateRandomNumbers = function() {
// call to public local method (this.updateOperators())
// and to a local private method (getRandomNumber())
this.updateOperators(getRandomNumber(), getRandomNumber())
}
// init
this.populateRandomNumbers()
}
// Mandatory for derived classes. Allows access to superior classes with
// more than 2 levels of inheritance ("grandfather" classes)
Randomizer.prototype = Object.create(Operators.prototype)
function Operations() {
Randomizer.call(this)
var self = this
//private
var IPT_RES = '#res'
var BTN_SUM = '#sum'
var BTN_SUBTRACT = '#subt'
var BTN_MULTIPLY = '#mult'
var BTN_DIVISION = '#div'
var BTN_CLEAN = '#clean'
var BTN_RAND = '#rand'
function calcSum() {
return self.x + self.y
}
function calcSubtraction() {
return self.x - self.y
}
function calcMultiplication() {
return self.x * self.y
}
function calcDivision() {
return self.x / self.y
}
function showRes(val) {
$(IPT_RES).val(val)
}
//public
this.sum = function() {
// call to 2 local private methods
showRes(calcSum())
}
this.subtract = function() {
showRes(calcSubtraction())
}
this.multiply = function() {
showRes(calcMultiplication())
}
this.division = function() {
showRes(calcDivision())
}
// init
$(BTN_SUM).on('click', function() { self.sum() })
$(BTN_SUBTRACT).on('click', function() { self.subtract() })
$(BTN_MULTIPLY).on('click', function() { self.multiply() })
$(BTN_DIVISION).on('click', function() { self.division() })
$(BTN_CLEAN).on('click', function() { self.clean() })
$(BTN_RAND).on('click', function() { self.populateRandomNumbers() })
}
Operations.prototype = Object.create(Randomizer.prototype)
var obj = new Operations()
If you're going to test it here is the html code:
X: <input id='x'>
<br>
Y: <input id='y'>
<br>
Res: <input id='res'>
<br>
<input id='sum' type='button' value='+'>
<input id='subt' type='button' value='-'>
<input id='mult' type='button' value='*'>
<input id='div' type='button' value='/'>
<input id='clean' type='button' value='C'>
<input id='rand' type='button' value='Rand'>
don't forget to add the jquery file.
Here is a JSFiddle with that code in it:
http://jsfiddle.net/vqqrf2cb/24/

Accessing this variable from method instance

How do you access the this object from another object instance?
var containerObj = {
Person: function(name){
this.name = name;
}
}
containerObj.Person.prototype.Bag = function(color){
this.color = color;
}
containerObj.Person.prototype.Bag.getOwnerName(){
return name; //I would like to access the name property of this instance of Person
}
var me = new Person("Asif");
var myBag = new me.Bag("black");
myBag.getOwnerName()// Want the method to return Asif
Don't put the constructor on the prototype of another class. Use a factory pattern:
function Person(name) {
this.name = name;
}
Person.prototype.makeBag = function(color) {
return new Bag(color, this);
};
function Bag(color, owner) {
this.color = color;
this.owner = owner;
}
Bag.prototype.getOwnerName = function() {
return this.owner.name;
};
var me = new Person("Asif");
var myBag = me.makeBag("black");
myBag.getOwnerName() // "Asif"
Related patterns to deal with this problem: Prototype for private sub-methods, Javascript - Is it a bad idea to use function constructors within closures?

Categories

Resources