I am trying to figure out how to have a private instance variable on my class that gets set by a parameter of a public method. In this case, though; it seems that outside of somePublicMethod myPrivateVar will be undefined. How can achieve what I am trying to do ?
MyClass = function() {
var myPrivateVar;
this.somePublicMethod(myPrivateVar) {
myPrivateVar = myPrivateVar //????
}
this.someOtherPublicMethod() {
somePrivateMethod();
}
function somePrivateMethod() {
myPrivateVar++;
}
}
The issue is you're shadowing the var myPrivateVar by giving the argument the same name, so only the argument variable is in scope:
this.somePublicMethod = function(myPrivateVar) {
myPrivateVar = myPrivateVar; // sets the argument to itself
}
You'll need to give one of them a different name to avoid shadowing:
this.somePublicMethod = function(inputVar) {
myPrivateVar = inputVar;
};
Otherwise, you'll need to contain one of them somehow:
MyClass = function () {
var locals = {
myPrivateVar: null
};
this.somePublicMethod = function (myPrivateVar) {
locals.myPrivateVar = myPrivateVar;
};
function somePrivateMethod() {
locals.myPrivateVar++;
}
};
Use this.myPrivateVar:
this.somePublicMethod = function(myPrivateVar) {
this.myPrivateVar = myPrivateVar;
}
To call the private method within the context of this, you can use:
this.somePublicMethod = function(myPrivateVar) {
this.myPrivateVar = myPrivateVar;
somePrivateMethod.call(this); // pass this as the context of the private method
}
function somePrivateMethod() {
this.myPrivateVar++;
}
Have you considered taking a slightly different route?
var MyClass = function(){
var bar = "private";
return {
setBar: function( newBar ) { bar = newBar; },
getBar: function() { return bar; }
}
};
When you new-up an instance of this class, the bar property will be private. However, it will still be accessible by the public setBar and getBar methods.
var inst = new MyClass;
console.log( inst.bar ); // undefined
console.log( inst.getBar() ); // 'private'
inst.setBar( 'accessible' );
console.log( inst.getBar() ); // 'accessible'
Related
Is it possible to call parent method in JavaScript class but to still have access to prototype methods from parent and child class. Here is code example:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod = function() {
// call baseInitMethod from Base class
}
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
var s = new Specific();
console.log(s.baseMethod());
console.log(s.baseInitMethod());
console.log(s.basePrototypeMethod());
console.log(s.specificMethod());
console.log(s.specificInitMethod());
console.log(s.specificPrototypeMethod());
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class but so that all function calls from above still works. Is that possible?
Your Specific.prototype object should inherit from the Base.prototype object. Currently you're copying over all its properties to the object with this code:
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
But you should actually use Object.create to establish a real prototype chain:
Specific.prototype = Object.create(Base.prototype);
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class
Yes. In your Specific constructor, you first need get Base's baseInitMethod instance method, before you overwrite the property of the instance:
function Specific() {
Base.call(this);
var parentInitMethod = this.baseInitMethod;
this.baseInitMethod = function() {
// call baseInitMethod from Base class:
parentInitMethod.call(this /*, arguments…*/);
}
…
}
so that all function calls from above still works.
I'm not sure what you mean by that exactly. The specificPrototypeMethod will always call the baseInitMethod of the current instance, which would be Specific's overwritten one not the original that was defined in Base.
Here is what you need to do:
var Base = function () {
};
Base.prototype.baseMethod = function () {
return 'baseMethod';
};
Base.prototype.baseInitMethod = function () {
return 'baseInitMethod';
};
Base.prototype.basePrototypeMethod = function () {
return "basePrototypeMethod";
};
var Specific = function () {
Base.apply(this, arguments);
};
Specific.prototype.baseInitMethod = function () {
Base.prototype.baseInitMethod.apply(this,arguments);
};
Specific.prototype.specificMethod = function () {
return 'specificMethod';
};
Specific.prototype.specificInitMethod = function () {
var basePrototypeMethodCallResult = Base.prototype.basePrototypeMethod.apply(this,arguments);
};
You're overwriting the baseInitMethod of Base inside Specific, with Specific's definition, so why would you ever want to call the Base version? If you simply remove the overwrite of the function you should call the Base definition:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod(); // calls the Base definition only
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
One might argue "Why always trying to mimic 'classical' behaviour and fuss with call and apply instead of embracing the prototype delegation pattern instead?"
Here is what I would code :
var Base = {
baseVariable1: "baseValue1",
baseVariable2: "baseValue2",
baseMethod: function () {
return 'baseMethod';
},
baseInitMethod: function () {
return 'baseInitMethod';
}
}
var Specific = Object.create(Base);
Specific.variable1 = "value1";
Specific.variable2 = "value2";
Specific.specificInitMethod = function () {
return 'specificInitMethod' + '-' + this.baseInitMethod();
}
Specific.specificMethod = function () {
return 'specificMethod' + '-' + this.baseInitMethod();
}
var s = Object.create(Specific);
console.log(s.baseInitMethod());
console.log(s.baseVariable1);
console.log(s.baseVariable2);
console.log(s.variable1);
console.log(s.variable2);
console.log(s.baseMethod());
console.log(s.specificInitMethod());
console.log(s.specificMethod());
class Parentable {
get parent() {
return this.__proto__.__proto__;
}
}
class A extends Parentable {
say() {
console.log('Hello from A');
}
}
class B extends A {
say() {
console.log('Im not A, I am B! But A send you a message:');
this.parent.say();
}
}
(new B()).say();
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
I have 2 Obj: I want to know that if they are Singleton?
a.
var OBJ = function () {
}
OBJ.prototype = {
setName : function (name) {
this.name = name;
},
getName : function () {
return this.name;
}
}
b.
var OBJ = {
setName : function (name) {
this.name = name;
},
getName : function () {
return this.name;
}
}
You can check it by creating two instances of class and compare them:
Print( a === b ); // prints: true
if prints true class is singleton
Or you can try this code for SingletonPattern:
function MyClass() {
if ( arguments.callee._singletonInstance )
return arguments.callee._singletonInstance;
arguments.callee._singletonInstance = this;
this.Foo = function() {
// ...
}
}
var a = new MyClass()
var b = MyClass()
Print( a === b ); // prints: true
Best Solution For Singleton Pattern
This will help you How to write a singleton class in javascript
function Cats() {
var names = [];
// Get the instance of the Cats class
// If there's none, instanciate one
var getInstance = function() {
if (!Cats.singletonInstance) {
Cats.singletonInstance = createInstance();
}
return Cats.singletonInstance;
}
// Create an instance of the Cats class
var createInstance = function() {
// Here, you return all public methods and variables
return {
add : function(name) {
names.push(name);
return this.names();
},
names : function() {
return names;
}
}
}
return getInstance();
}
More on http://www.javascriptkata.com/2009/09/30/how-to-write-a-singleton-class-in-javascript/
Also it can be possible duplicate of Javascript: best Singleton pattern and Simplest/Cleanest way to implement singleton in JavaScript?
How can I go about making a child class override a privileged method of a base class?
If its not possible, is there another way to achieve what I am trying to accomplish in the simple code example below?
I cannot convert the baseclass function parseXML() to public because it requires access to private variables
function BaseClass()
{
var map = {};
// I cannot make this function public BECAUSE it accesses & changes private variables
this.parseXML = function( key, value )
{
alert("BaseClass::parseXML()");
map[key] = value;
}
}
function ChildClass()
{
BaseClass.call(this);
this.parseXML = function( key, value, otherData )
{
alert("ChildClass()::parseXML()");
// How can I call the base class function parseXML()?
//this.parseXML(); // calls this function not the parent function
//MyClass.prototype.doStuff.call
BaseClass.prototype.parseXML.call(this, key, value); // fails
//BaseClass.prototype.parseXML(); // fails
// perform specialised actions here with otherData
}
}
ChildClass.prototype = new BaseClass;
var a = new ChildClass();
a.parseXML();
function BaseClass() {
var map = {};
this.parseXML = function(key, value) {
alert("BaseClass::parseXML()");
map[key] = value;
}
}
function ChildClass() {
BaseClass.call(this);
var parseXML = this.parseXML;
this.parseXML = function(key, value, otherData) {
alert("ChildClass()::parseXML()");
parseXML.call(this, key, value);
}
}
ChildClass.prototype = new BaseClass;
var a = new ChildClass();
a.parseXML();
Live Example
Basically you cache the privileged method (which is only defined on the object) and then call it inside the new function you assign to the privileged method name.
However a more elegant solution would be:
function BaseClass() {
this._map = {};
};
BaseClass.prototype.parseXML = function(key, value) {
alert("BaseClass::parseXML()");
this._map[key] = value;
}
function ChildClass() {
BaseClass.call(this);
}
ChildClass.prototype = Object.create(BaseClass.prototype);
ChildClass.prototype.parseXML = function(key, value, otherData) {
alert("ChildClass()::parseXML()");
BaseClass.prototype.parseXML.call(this, key, value);
}
var a = new ChildClass();
a.parseXML();
Live Example
Also bonus implementation using pd
IMO, you need to use a Javascript library like Ext Js to simplify this task. Anyway, the following example illustrates how you can write some helper methods. It's a part of an unreleased open source project that I'm working on.
var JWObject = (function () {
var jwobj = function (){};
jwobj.prototype = { };
return jwobj;
})();
var Prototype = (function () {
var scopeQueue = [ window ];
return {
beginScope: function (namespace) {
var parts = namespace.split('.');
for (var i = 0; i < parts.length; i++) {
var name = parts[i],
parent = this.getScope(),
part = parent[name];
if (part && !part.__namespace) {
throw Error('/* ERROR MESSAGE */');
}
scopeQueue.push(parent[name] = (part || { __namespace: true }));
}
},
endScope: function () {
if (scopeQueue.length > 1) {
scopeQueue.pop();
}
},
getScope: function () {
return scopeQueue.pick();
},
define: function (name, members) {
var scope = this.getScope();
if (scope[name]) {
throw Error('The prototype already exist.');
}
this.extend(members, {
scope: scope,
extend: JWObject,
statics: {}
});
// Getting constructor
var ctor = (members.constructor === Object) ? function() { } : members.constructor;
delete members.constructor;
if (typeof members.extend === 'string') {
members.extend = scope[members.extend];
}
if (!members.extend) {
throw Error('The base class is not specified.');
}
// Deriving from parent type
ctor.prototype = new members.extend();
members.super = members.extend.prototype;
delete members.extend;
members.statics.__class = true;
this.extend(ctor, members.statics, true);
delete members.statics;
// Adding new members
this.extend(ctor.prototype, members, true);
// Adding and returning the created prototype
return scope[name] = ctor;
},
extend: function (expando, members, override) {
for (var m in members) {
if (override || !expando[m]) {
expando[m] = members[m];
}
}
}
};
})();
Prototype.extend(Array.prototype, {
pick: function() {
return this[this.length - 1];
}
});
Here is the result:
Prototype.beginScope('Sample');
/**
* Prototype: Sample.Plugin
*/
Prototype.define('Plugin', {
init: function() {
alert('init!');
}
});
Prototype.beginScope('Extension');
/**
* Prototype: Sample.Extensions.Plugin
* Extend : Sample.Plugin
*/
Prototype.define('Foo', {
extend: Sample.Plugin,
init: function() {
this.super.init.call(this);
alert('child: init!');
},
fun: function() {
this.init();
},
statics: {
create: function() {
return new Sample.Extension.Foo();
}
}
});
Prototype.endScope();
Prototype.endScope();
As you can see in the preceding code, the Prototype object provides some functionality to defining a namespace (Prototype.beginScope, Prototype.endScope and Prototype.getScope) or defining a prototype (Prototype.define).
You can inherit a prototype from another using extend like java.
Prototype.define('Foo', {
extend: Sample.Plugin,
Or call the base class method as follows:
init: function() {
this.super.init.call(this);
Also, every prototype you define with above code will be derived from JWObject by default.
I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());