First Attempt at Javascript Objects & Inheritance: is it correct - javascript

I am attempting to learn how to create classes in Javascript & how to perform object inheritance. I have followed some tutorials but I am not sure if my code is correct.
Am I creating public functions & attributes correctly? If not, what should I change?
Am I creating privileged functions & attributes correctly? If not, what should I change?
Am I creating private functions & attributes correctly? If not, what should I change?
Am I overriding functions correctly?
Am I performing inheritance correctly?
If theres anything wrong can you show me how the code should be?
Heres my simple code that creates a base class then a child class:
/* Base Object Class */
function BaseClass( /*string*/ objType )
{
/* Public: */
this.name = "blah";
BaseClass.prototype.getName = function()
{
return this.name;
}
BaseClass.prototype.setName = function( newName )
{
var oldName = this.name;
this.name = newName;
return oldName;
}
/* Private: */
var attributeMap = {};
this.constructor = function()
{
// this objects default constructor. Is this correct?
attributeMap["type"] = objType;
attributeMap["uniqueID"] = "Base"+(++INSTANCE_COUNT);
}
/* Privileged: */
// Will an object that inherits from this class be able to override the following functions?
// Or do I have to make these functions public in order to override them?
this.toString = function()
{
var s = "";
for (var attrib in attributeMap)
{
s += attrib + ": " + attributeMap[attrib] + ", ";
}
return s;
}
this.getType = function()
{
return attributeMap["type"];
}
this.renderObject = function()
{
// TODO: render object on HTML5 canvas
}
this.parseXMLNode = function( /*XML Node*/ nodeXML, /*string*/ objType )
{
var attribs = nodeXML.attributes;
for (var i=0; i<attribs.length; i++)
{
attributeMap[ attribs[i].nodeName ] = attribs[i].nodeValue;
}
// store children
if ( nodeXML.hasChildNodes() )
{
attributeMap["children"] = nodeXML.childNodes;
}
reformatObjectInnerHTML();
}
}
// Static Variables //
BaseObject.INSTANCE_COUNT = 0;
// My Child Class //
ChildClass.prototype = new BaseObject( objType ); // make ChildClass inherit from BaseClass
ChildClass.prototype.constructor = function(ObjType) // Make the ChildClass call the BaseClass constructor
{
BaseObject.prototype.constructor.call(this, objType);
}
function ChildClass( /*string*/ objType )
{
/* Privileged: */
// Attempt to override BaseClass function renderObject()
this.renderObject = function()
{
alert("ChildClass::renderObject();");
// Does this override the BaseClass renderObject() function?
}
}

How to Achieve Private, Public, Privileged members in Javascript
Though I'm not advising you to write code like this. JavaScript is different from C++. Don't write C++ code in JavaScript.

Seriously inheritance in JS is just not that useful. Copy the functions to another object if you need them there, are just call them in context of that object. I do plenty of OOP in Java land, but inheritance can easily be avoided in javascript through the use context and callbacks. That is if when you think you need an inheritance hierarchy, you probably just need a callback or call the function in a different context.
But to answer your question that is not the "correct" way check out javascript garden
function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// Set Bar's prototype to a new instance of Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// Make sure to list Bar as the actual constructor
Bar.prototype.constructor = Bar;
var test = new Bar() // create a new bar instance

Related

Prototype for private sub-methods

I have code that looks like this:
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
}
Adding methods to baseClass is fine, I just use
baseClass.prototype.newMethod = function () {
// NEW CODE
}
My question is how should I add methods to subClass? Is the only way to simply make it a public method?
######## EDIT ##############
OK so I've rearranged the code so the subClass is outside the baseClass. I pass in baseClass so subClass can still access the properties of the instance of baseClass.
var baseClass = function() {
var base = this;
this.property_a = 1;
this.property_b = 5;
var sub = new subClass(base);
// CODE
}
var subClass = function(parent) {
var sub = this;
this.property_c = 1;
this.method_a = function() {
return sub.property_c + parent.property_a;
}
// MORE CODE
}
this is fine and works, but now I have a new problem of when I add a method using prototype:
subClass.prototype.method_b = function(){
return sub.property_c + parent.property_b;
}
I get an error saying parent isn't defined.
Basically I have a fairly simple web application that has two sides, a viewing side and an editing side. I build the base class which includes everything necessary for viewing, and I want to add the methods required for editing in a different file so they're only loaded when a user is on the editing page.
Why do you declare that subclass in the base class? Doesn't make sense to me.
You can add to the subclass's prototype whereever it is in you scope. In your code it would be
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
subClass.prototype = {
...
}
}
But I'd suggest to put it out of the base class constructor. If you want it private for some reason, add a closure:
(function(){
baseClass = function() { // public
// CODE
}
baseClass.prototype = {...};
var subClass = function() { // private
// MORE CODE
}
subClass.prototype = Object.create(baseClass.prototype);
subClass.prototype.newMethod = function () { ... }
})()
EDIT to answer the extended question:
Ah, subClass doesn't inherit from baseClass! We had expected that, otherwise it may be OK to have it inside the constructor. Then, the same prototype could have been added to each of the different subClass constructors:
var subproto = {
method_b: = function(){
// manipulate "this"
},
...
};
function baseClass() {
// some code
function sub() {
// is a constructor for subs which belong to this specif base intance
...
}
sub.prototype = subproto; // the sub constructors of each base instance
// have the same prototype
var x = new sub(),
y = new sub(); // example usage of the sub constructor
}
baseClass.prototype = {...}
Else, if you want one common sub constructor (outside of function baseClass), you may give the base instance the sub belongs to as an argument to the constructor - as you did. Of course the sub (both internal and external methods) can only access public properties of that base instance.
The mistake you made in your rearranged code is that your prototype ("external") methods tried to access the private parent variable from the sub constructor. As you say, "error saying parent isn't defined".
var subClass = function(parent) {
var sub = this;
this.parent = parent; // make it public
this.property_c = 1;
this.method_a = function() {
return sub.property_c + parent.property_a;
}
// MORE CODE
}
subClass.prototype.method_b = function(){
// prototype functions can only access public properties
// i.e. privileged methods, public attributes and other prototype properties
return this.property_c + this.parent.property_b;
}
You will have to define the methods in the same context as you define subClass:
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
subClass.prototype.newMethod = function () { ... }
}
If that's not possible, then you will need to expose subClass to the appropriate context or provide a mechanism from baseClass to extend subClass.
If you really want to keep the subclass private, you could hide the definitions in a closure:
var BaseClass = (function() {
function BaseClass() { ... };
function SubClass() { ... };
BaseClass.prototype.foo = function() { ... };
SubClass.prototype.foo = function() { ... };
return BaseClass;
})();
I have personally found this kind of closure-enforced protection to be more trouble than it's worth (ex, makes debugging more difficult)… But if you wanted to do it, that's how you would.

javascript inheritance with protected variables

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

Question about a particular pattern of Javascript class definition

Recently I saw the following code that creates a class in javascript:
var Model.Foo = function(){
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
if(typeof Model.Foo._init === 'undefined'){
Model.Foo.prototype = {
func1 : function(){ //...},
func2 : function(){ //... },
//other prototype functions
}
}
Model.Foo._init = true;
}
// Instantiate and use the class as follows:
var foo = new Model.Foo(); foo.func1();
I guess the _init variable is used to make sure we don't define the prototypes again. Also, I feel the code is more readable since I am placing everything in a function block (so in oop-speak, all attributes and methods are in one place).
Do you see any issues with the code above? Any pitfalls of using this pattern if I need to create lots of classes in a big project?
This is a weird Javascript pattern that I would never use to develop object-oriented JS code. For one thing, Model.Foo._init === 'undefined' never evaluates to true if Model.Foo._init is anything but the string 'undefined'; therefore, the code
Model.Foo.prototype = {
func1 : function(){ /* ... */},
func2 : function(){ /* ... */},
//other prototype functions
}
will not run unless that condition holds true. (Perhaps the author meant to add a typeof, as in typeof Model.Foo._init === 'undefined'? I don't know.)
Addressing your concern about "[making] sure we don't define the prototypes again", this is already achieved with:
Model.Foo = function() {
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
};
Model.Foo.prototype = {
func1 : function() { /* ... */},
func2 : function() { /* ... */}
//,other prototype functions
};
// Instantiate and use the class as follows:
var foo = new Model.Foo();
foo.func1();
which is along the lines of what I recommend if you aren't using a framework.
Basically, the answer to your question is: if you use this non-standard pattern for development, then other programmers, maybe even yourself a few months later, will find it difficult to extend and work with.
It just seems unnecessarily complex. You need to be disciplined to not use any parameters or local variables of Model.Foo in the implementation of the prototype extension. Its odd to overwrite the entire .prototype object and not just add individual members as well. Why not just do this the normal way?
var Model.Foo = function(){
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
}
Model.Foo.prototype.func1 = function(){ //...};
Model.Foo.prototype.func2 = function(){ //... };
alternate allowing per-instance member variables private
var Model.Foo = function(){
// private stuff
var a, b;
// public properties
this.attr1 = '';
this.attr2 = '';
this.func1 = function(){ //...};
this.func2 = function(){ //... };
}
A few things stand out as potentially troublesome:
Foo.prototype is set to a simple object, which can't extend anything using this pattern.
Where is the "private stuff" used? Every time you create a new object, you create new private variables, which seemingly can only be used in the functions defined in Foo.prototype, which should only be run once.
It's kind of a mess, and there are details/examples all over the web of better was to do this.
The following example illustrates a pattern that I personally developed over time.
It exploits scoping to allow private fields and methods.
Employee = (function(){
// private static field
var staticVar;
// class function a.k.a. constructor
function cls()
{
// private instance field
var name = "";
var self = this;
// public instance field
this.age = 10;
// private instance method
function increment()
{
// must use self instead of this
self.age ++;
}
// public instance method
this.getName = function(){
return cls.capitalize(name);
};
this.setName = function(name2){
name = name2;
};
this.increment = function(){
increment();
};
this.getAge = function(){
return this.age;
};
}
// public static field
cls.staticVar = 0;
// public static method
cls.capitalize = function(name){
return name.substring(0, 1).toUpperCase() +
name.substring(1).toLowerCase();
};
// private static method
function createWithName(name)
{
var obj = new cls();
obj.setName(cls.capitalize(name));
return obj;
}
return cls;
})();
john = new Employee();
john.setName("john");
mary = new Employee();
mary.setName("mary");
mary.increment();
alert("John's name: " + john.getName() + ", age==10: "+john.getAge());
alert("Mary's name: " + mary.getName() + ", age==11: "+mary.getAge());

Nested class in javascript, inheritance of private methods

i'm quite a newbie in javascript, and i'm spending some time trying to create namespaced objects in js.
Now, that's what i'm trying to do:
MainObject = function() {
var privateVariable = "i'm private";
var privateMethod = function() {
// doSomething
}
this.publicMethod = function() {
// doPublicSomething
}
}
MainObject.prototype.nested = function() {
this.publicNestedMethod = function() {
// that's not working at all
this.privateMethod(privateVariable);
}
}
MyObject = new MainObject();
MyObject.publicMethod();
MyObject.publicNestedMethod();
I tried to include the nested class inside the first one, but it's not working also if i try:
this.nested = function() {
var mainObject = this;
return {
publicNestedMethod = function() {
mainObject.privateMethod();
}
}
}();
Someone can help me please? i'm gonna loose my mind on this.
Phaedra.
Closures are a lexical feature, not a semantic one. If the object is outside the lexical scope of another, it can no longer be "nested" and access the former's local variables. In the code of your nested function/class, there's no such thing as this.privateMethod, because privateMethod is never made to be a property of MainObject. It's simply a local variable inside a function.
There's no such things as "private properties", "private methods" or "private members" in JavaScript. Hell, there's no such thing as a "class". Some people like to emulate private members using local variables as above, but doing so results in cases like this, where the discrepancy between the two concepts comes and bites one in the behind.
To conclude, it is a bad idea to write Java code, with all its OO techniques in JS, just as it is a bad idea to write C code, with all its pointers and unbounded buffers, in C#. Sure, in both cases you can do it, but you would be failing to appreciate and exploit the language's features this way.
And now that I'm done with the rant, you can do something like this to get "namespaced" functions:
MainObject = function() {
var privateVariable = "I'm private";
var privateMethod = function() {
alert('Private');
}
this.publicMethod = function() {
alert('Public');
}
this.nested = {
publicNestedMethod: function() {
privateMethod();
}
};
// or
this.nested = (function() {
var nestedPrivate = 5;
return {
publicNestedMethod: function() {
alert(nestedPrivate);
privateMethod();
}
};
})();
}
MyObject = new MainObject();
MyObject.publicMethod();
MyObject.nested.publicNestedMethod();​
Using the convention of underscore for "private" methods is a reasonable way to keep things organized.
MainObject = function() {
this._privateVariable = "i'm private";
this._privateMethod = function() {
// doSomething
}
this.publicMethod = function() {
// doPublicSomething
}
}
Well to provide the benefit of prototypal inheritance where all "subclasses" share a single instance of the method in prototype, but to ALSO provide the feature of inheriting private instances...
I came up with:
function Person(name,latentPower){
var privatesForChildren = { password:"xyz"
,latentPower:"invisibility"}
this.inherit = function(){
for(v in privatesForChildren){
eval("var " + v + "=privatesForChildren['" + v + "'];");
}
}
this.name = name;
this.revealName = function(){ alert("My name is" + this.name + "."); }
this.revealPowers = function(){ alert("I'm normal."); }
}
function Mutant(name,latentPower,fuel){
this.inherit.call(this); // Inherit private instance variables
var fuel = fuel;
this.name = name;
this.revealPowers = function(){
alert("I manifest the powers of " + latentPower + " when I " + fuel + ".");
}
}
Mutant.prototype = new Person;
Mutant.prototype.constructor = Mutant;
bob = new Person("Bob","telekenesis");
jim = new Mutant("Jim","nausea","eat pizza");
buford = new Mutant("Buford","Teflon Man","breathe");
jim.revealName(); //Inherited properly from prototype
bob.revealPowers();
jim.revealPowers();
buford.revealPowers(); //distinct from Jim's so is an "instance var"
alert(bob.latentPower); //returns undefined
alert(buford.latentPower); //returns undefined, so is "private".
How useful is that?
JavaScript Classes and Inheritance (ES6)
According to ES6, you can use JavaScript classes and inheritance to accomplish what you need.
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
I'm showing the examples below with variables, but it can be applied also to functions.
Inheritance (1st Approach)
This solution can only be used with getters for your private variables, otherwise your subclass will not get access to them.
class Main {
constructor() {
let privateVariable = "private";
this.publicVariable = "public";
this.getPrivateVariable = () => {
return privateVariable;
}
}
}
Main.Sub = class Sub extends Main {
getAllVariables() {
return this.publicVariable + "-" + this.getPrivateVariable();
}
}
// Testing...
let main = new Main();
let sub = new Main.Sub();
console.log(main.privateVariable); // undefined
console.log(main.publicVariable); // "public"
console.log(sub.privateVariable); // undefined
console.log(sub.publicVariable); // "public"
console.log(main.getPrivateVariable()); // "private"
console.log(sub.getPrivateVariable()); // "private"
console.log(sub.getAllVariables()) // "public-private"
Nesting (2nd Approach)
Maybe this solution is better for you because it doesn't expose your private variables outside the Main and Nested classes.
class Main {
constructor() {
let privateVariable = "private";
this.publicVariable = "public";
Main.Nested = class Nested extends Main {
getAllVariables() {
return this.publicVariable + "-" + privateVariable;
}
}
}
}
// Testing...
let main = new Main();
let nested = new Main.Nested();
console.log(main.privateVariable); // undefined
console.log(main.publicVariable); // "public"
console.log(nested.privateVariable); // undefined
console.log(nested.publicVariable); // "public"
console.log(main.getPrivateVariable); // undefined
console.log(nested.getPrivateVariable); // undefined
console.log(nested.getAllVariables()) // "public-private"
What OO system lets you inherit private methods? Part of being private is being unaccessible from other objects.
In JS in particular, "private members" are really just local variables of the function where they are declared. JS doesn't have typical OO notions of "class", "inheritance", "public", and "private", so you can't expect to copy your OOP techniques verbatim from other OOP languages.
It is a convention. You can imitate OO Java techniques like private members but that's not recommended. You can imitate in this way:
MyFunction = function(options){
var private = {};
//to reference MyFunction as a context
var that = this;
function privateFunctionThatCallPublicMethod(){
that.publicFunction("hello");
}
this.publicFunction = function(params){
alert(params + " " + private);
}
...
}
var instance = new MyFunction({oneOption:'fsdfsad'});
This is the bests approach i found to emulate OO Java Techniques...
But there is a problem, is very inefficient...
You must use prototype instead, because otherwise it would create one object per function per instance of the "class".
MyFunction = function(options){
this._private = {};
}
MyFunction.prototype._privateFunctionThatCallPublicMethod = function(){
this.publicFunction("hello");
}
MyFunction.prototype.publicFunction = function(params){
alert(params + " " + this._private);
}
Like you think private members are (in this way) a convention.
Also, there is another thing you must know...
When you pass a function of an object as a parameter to another function you must bind the context of the function...
function bind(fnThis, fn) {
return function(){
return fn.apply(fnThis, arguments);
};
}
function makeSomething(callback){
callback("hello");
}
var instance = new MyFunction();
makeSomething(bind(instance, instance.publicFunction));
This is because you must bind "this" as instance in the body of the publicFunction, otherwise is gonna be "window" instead.

JavaScript private methods

To make a JavaScript class with a public method I'd do something like:
function Restaurant() {}
Restaurant.prototype.buy_food = function(){
// something here
}
Restaurant.prototype.use_restroom = function(){
// something here
}
That way users of my class can:
var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();
How do I create a private method that can be called by the buy_food and use_restroom methods but not externally by users of the class?
In other words, I want my method implementation to be able to do:
Restaurant.prototype.use_restroom = function() {
this.private_stuff();
}
But this shouldn't work:
var r = new Restaurant();
r.private_stuff();
How do I define private_stuff as a private method so both of these hold true?
I've read Doug Crockford's writeup a few times but it doesn't seem like "private" methods can be called by public methods and "privileged" methods can be called externally.
You can do it, but the downside is that it can't be part of the prototype:
function Restaurant() {
var myPrivateVar;
var private_stuff = function() { // Only visible inside Restaurant()
myPrivateVar = "I can set this here!";
}
this.use_restroom = function() { // use_restroom is visible to all
private_stuff();
}
this.buy_food = function() { // buy_food is visible to all
private_stuff();
}
}
Using self invoking function and call
JavaScript uses prototypes and does't have classes (or methods for that matter) like Object Oriented languages. A JavaScript developer need to think in JavaScript.
Wikipedia quote:
Unlike many object-oriented languages, there is no distinction between
a function definition and a method definition. Rather, the distinction
occurs during function calling; when a function is called as a method
of an object, the function's local this keyword is bound to that
object for that invocation.
Solution using a self invoking function and the call function to call the private "method" :
var MyObject = (function () {
// Constructor
function MyObject(foo) {
this._foo = foo;
}
function privateFun(prefix) {
return prefix + this._foo;
}
MyObject.prototype.publicFun = function () {
return privateFun.call(this, ">>");
}
return MyObject;
}());
var myObject = new MyObject("bar");
myObject.publicFun(); // Returns ">>bar"
myObject.privateFun(">>"); // ReferenceError: private is not defined
The call function allows us to call the private function with the appropriate context (this).
Simpler with Node.js
If you are using Node.js, you don't need the IIFE because you can take advantage of the module loading system:
function MyObject(foo) {
this._foo = foo;
}
function privateFun(prefix) {
return prefix + this._foo;
}
MyObject.prototype.publicFun = function () {
return privateFun.call(this, ">>");
}
module.exports= MyObject;
Load the file:
var MyObject = require("./MyObject");
var myObject = new MyObject("bar");
myObject.publicFun(); // Returns ">>bar"
myObject.privateFun(">>"); // ReferenceError: private is not defined
(new!) Native private methods in future JavaScript versions
TC39 private methods and getter/setters for JavaScript classes proposal is stage 3. That means any time soon, JavaScript will implement private methods natively!
Note that JavaScript private class fields already exists in modern JavaScript versions.
Here is an example of how it is used:
class MyObject {
// Private field
#foo;
constructor(foo) {
this.#foo = foo;
}
#privateFun(prefix) {
return prefix + this.#foo;
}
publicFun() {
return this.#privateFun(">>");
}
}
You may need a JavaScript transpiler/compiler to run this code on old JavaScript engines.
PS: If you wonder why the # prefix, read this.
(deprecated) ES7 with the Bind Operator
Warning: The bind operator TC39 proposition is near dead https://github.com/tc39/proposal-bind-operator/issues/53#issuecomment-374271822
The bind operator :: is an ECMAScript proposal and is implemented in Babel (stage 0).
export default class MyObject {
constructor (foo) {
this._foo = foo;
}
publicFun () {
return this::privateFun(">>");
}
}
function privateFun (prefix) {
return prefix + this._foo;
}
You can simulate private methods like this:
function Restaurant() {
}
Restaurant.prototype = (function() {
var private_stuff = function() {
// Private code here
};
return {
constructor:Restaurant,
use_restroom:function() {
private_stuff();
}
};
})();
var r = new Restaurant();
// This will work:
r.use_restroom();
// This will cause an error:
r.private_stuff();
More information on this technique here: http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html
In these situations when you have a public API, and you would like private and public methods/properties, I always use the Module Pattern. This pattern was made popular within the YUI library, and the details can be found here:
http://yuiblog.com/blog/2007/06/12/module-pattern/
It is really straightforward, and easy for other developers to comprehend. For a simple example:
var MYLIB = function() {
var aPrivateProperty = true;
var aPrivateMethod = function() {
// some code here...
};
return {
aPublicMethod : function() {
aPrivateMethod(); // okay
// some code here...
},
aPublicProperty : true
};
}();
MYLIB.aPrivateMethod() // not okay
MYLIB.aPublicMethod() // okay
Here is the class which I created to understand what Douglas Crockford's has suggested in his site Private Members in JavaScript
function Employee(id, name) { //Constructor
//Public member variables
this.id = id;
this.name = name;
//Private member variables
var fName;
var lName;
var that = this;
//By convention, we create a private variable 'that'. This is used to
//make the object available to the private methods.
//Private function
function setFName(pfname) {
fName = pfname;
alert('setFName called');
}
//Privileged function
this.setLName = function (plName, pfname) {
lName = plName; //Has access to private variables
setFName(pfname); //Has access to private function
alert('setLName called ' + this.id); //Has access to member variables
}
//Another privileged member has access to both member variables and private variables
//Note access of this.dataOfBirth created by public member setDateOfBirth
this.toString = function () {
return 'toString called ' + this.id + ' ' + this.name + ' ' + fName + ' ' + lName + ' ' + this.dataOfBirth;
}
}
//Public function has access to member variable and can create on too but does not have access to private variable
Employee.prototype.setDateOfBirth = function (dob) {
alert('setDateOfBirth called ' + this.id);
this.dataOfBirth = dob; //Creates new public member note this is accessed by toString
//alert(fName); //Does not have access to private member
}
$(document).ready()
{
var employee = new Employee(5, 'Shyam'); //Create a new object and initialize it with constructor
employee.setLName('Bhaskar', 'Ram'); //Call privileged function
employee.setDateOfBirth('1/1/2000'); //Call public function
employee.id = 9; //Set up member value
//employee.setFName('Ram'); //can not call Private Privileged method
alert(employee.toString()); //See the changed object
}
ES12 Private Methods
You can do this now with es12 private methods. You just need to add a # before the method name.
class ClassWithPrivateMethod {
#privateMethod() {
return 'hello world';
}
getPrivateMessage() {
return #privateMethod();
}
}
I conjured up this: EDIT: Actually, someone has linked to a identical solution. Duh!
var Car = function() {
}
Car.prototype = (function() {
var hotWire = function() {
// Private code *with* access to public properties through 'this'
alert( this.drive() ); // Alerts 'Vroom!'
}
return {
steal: function() {
hotWire.call( this ); // Call a private method
},
drive: function() {
return 'Vroom!';
}
};
})();
var getAwayVechile = new Car();
hotWire(); // Not allowed
getAwayVechile.hotWire(); // Not allowed
getAwayVechile.steal(); // Alerts 'Vroom!'
ES2021 / ES12 - Private Methods
Private method names start with a hash # prefix and can be accessed only inside the class where it is defined.
class Restaurant {
// private method
#private_stuff() {
console.log("private stuff");
}
// public method
buy_food() {
this.#private_stuff();
}
};
const restaurant = new Restaurant();
restaurant.buy_food(); // "private stuff";
restaurant.private_stuff(); // Uncaught TypeError: restaurant.private_stuff is not a function
I think such questions come up again and again because of the lack of understanding of the closures. Сlosures is most important thing in JS. Every JS programmer have to feel the essence of it.
1. First of all we need to make separate scope (closure).
function () {
}
2. In this area, we can do whatever we want. And no one will know about it.
function () {
var name,
secretSkills = {
pizza: function () { return new Pizza() },
sushi: function () { return new Sushi() }
}
function Restaurant(_name) {
name = _name
}
Restaurant.prototype.getFood = function (name) {
return name in secretSkills ? secretSkills[name]() : null
}
}
3. For the world to know about our restaurant class,
we have to return it from the closure.
var Restaurant = (function () {
// Restaurant definition
return Restaurant
})()
4. At the end, we have:
var Restaurant = (function () {
var name,
secretSkills = {
pizza: function () { return new Pizza() },
sushi: function () { return new Sushi() }
}
function Restaurant(_name) {
name = _name
}
Restaurant.prototype.getFood = function (name) {
return name in secretSkills ? secretSkills[name]() : null
}
return Restaurant
})()
5. Also, this approach has potential for inheritance and templating
// Abstract class
function AbstractRestaurant(skills) {
var name
function Restaurant(_name) {
name = _name
}
Restaurant.prototype.getFood = function (name) {
return skills && name in skills ? skills[name]() : null
}
return Restaurant
}
// Concrete classes
SushiRestaurant = AbstractRestaurant({
sushi: function() { return new Sushi() }
})
PizzaRestaurant = AbstractRestaurant({
pizza: function() { return new Pizza() }
})
var r1 = new SushiRestaurant('Yo! Sushi'),
r2 = new PizzaRestaurant('Dominos Pizza')
r1.getFood('sushi')
r2.getFood('pizza')
I hope this helps someone better understand this subject
Personally, I prefer the following pattern for creating classes in JavaScript :
var myClass = (function() {
// Private class properties go here
var blueprint = function() {
// Private instance properties go here
...
};
blueprint.prototype = {
// Public class properties go here
...
};
return {
// Public class properties go here
create : function() { return new blueprint(); }
...
};
})();
As you can see, it allows you to define both class properties and instance properties, each of which can be public and private.
Demo
var Restaurant = function() {
var totalfoodcount = 0; // Private class property
var totalrestroomcount = 0; // Private class property
var Restaurant = function(name){
var foodcount = 0; // Private instance property
var restroomcount = 0; // Private instance property
this.name = name
this.incrementFoodCount = function() {
foodcount++;
totalfoodcount++;
this.printStatus();
};
this.incrementRestroomCount = function() {
restroomcount++;
totalrestroomcount++;
this.printStatus();
};
this.getRestroomCount = function() {
return restroomcount;
},
this.getFoodCount = function() {
return foodcount;
}
};
Restaurant.prototype = {
name : '',
buy_food : function(){
this.incrementFoodCount();
},
use_restroom : function(){
this.incrementRestroomCount();
},
getTotalRestroomCount : function() {
return totalrestroomcount;
},
getTotalFoodCount : function() {
return totalfoodcount;
},
printStatus : function() {
document.body.innerHTML
+= '<h3>Buying food at '+this.name+'</h3>'
+ '<ul>'
+ '<li>Restroom count at ' + this.name + ' : '+ this.getRestroomCount() + '</li>'
+ '<li>Food count at ' + this.name + ' : ' + this.getFoodCount() + '</li>'
+ '<li>Total restroom count : '+ this.getTotalRestroomCount() + '</li>'
+ '<li>Total food count : '+ this.getTotalFoodCount() + '</li>'
+ '</ul>';
}
};
return { // Singleton public properties
create : function(name) {
return new Restaurant(name);
},
printStatus : function() {
document.body.innerHTML
+= '<hr />'
+ '<h3>Overview</h3>'
+ '<ul>'
+ '<li>Total restroom count : '+ Restaurant.prototype.getTotalRestroomCount() + '</li>'
+ '<li>Total food count : '+ Restaurant.prototype.getTotalFoodCount() + '</li>'
+ '</ul>'
+ '<hr />';
}
};
}();
var Wendys = Restaurant.create("Wendy's");
var McDonalds = Restaurant.create("McDonald's");
var KFC = Restaurant.create("KFC");
var BurgerKing = Restaurant.create("Burger King");
Restaurant.printStatus();
Wendys.buy_food();
Wendys.use_restroom();
KFC.use_restroom();
KFC.use_restroom();
Wendys.use_restroom();
McDonalds.buy_food();
BurgerKing.buy_food();
Restaurant.printStatus();
BurgerKing.buy_food();
Wendys.use_restroom();
McDonalds.buy_food();
KFC.buy_food();
Wendys.buy_food();
BurgerKing.buy_food();
McDonalds.buy_food();
Restaurant.printStatus();
See also this Fiddle.
All of this closure will cost you. Make sure you test the speed implications especially in IE. You will find you are better off with a naming convention. There are still a lot of corporate web users out there that are forced to use IE6...
Don't be so verbose. It's Javascript. Use a Naming Convention.
After years of working in es6 classes, I recently started work on an es5 project (using requireJS which is already very verbose-looking). I've been over and over all the strategies mentioned here and it all basically boils down to use a naming convention:
Javascript doesn't have scope keywords like private. Other developers entering Javascript will know this upfront. Therefore, a simple naming convention is more than sufficient. A simple naming convention of prefixing with an underscore solves the problem of both private properties and private methods.
Let's take advantage of the Prototype for speed reasons, but lets not get anymore verbose than that. Let's try to keep the es5 "class" looking as closely to what we might expect in other backend languages (and treat every file as a class, even if we don't need to return an instance).
Let's demonstrate with a more realistic module situation (we'll use old es5 and old requireJs).
my-tooltip.js
define([
'tooltip'
],
function(
tooltip
){
function MyTooltip() {
// Later, if needed, we can remove the underscore on some
// of these (make public) and allow clients of our class
// to set them.
this._selector = "#my-tooltip"
this._template = 'Hello from inside my tooltip!';
this._initTooltip();
}
MyTooltip.prototype = {
constructor: MyTooltip,
_initTooltip: function () {
new tooltip.tooltip(this._selector, {
content: this._template,
closeOnClick: true,
closeButton: true
});
}
}
return {
init: function init() {
new MyTooltip(); // <-- Our constructor adds our tooltip to the DOM so not much we need to do after instantiation.
}
// You could instead return a new instantiation,
// if later you do more with this class.
/*
create: function create() {
return new MyTooltip();
}
*/
}
});
Take any of the solutions that follow Crockford's private or priviledged pattern. For example:
function Foo(x) {
var y = 5;
var bar = function() {
return y * x;
};
this.public = function(z) {
return bar() + x * z;
};
}
In any case where the attacker has no "execute" right on the JS context he has no way of accessing any "public" or "private" fields or methods. In case the attacker does have that access he can execute this one-liner:
eval("Foo = " + Foo.toString().replace(
/{/, "{ this.eval = function(code) { return eval(code); }; "
));
Note that the above code is generic to all constructor-type-privacy. It will fail with some of the solutions here but it should be clear that pretty much all of the closure based solutions can be broken like this with different replace() parameters.
After this is executed any object created with new Foo() is going to have an eval method which can be called to return or change values or methods defined in the constructor's closure, e.g.:
f = new Foo(99);
f.eval("x");
f.eval("y");
f.eval("x = 8");
The only problem I can see with this that it won't work for cases where there is only one instance and it's created on load. But then there is no reason to actually define a prototype and in that case the attacker can simply recreate the object instead of the constructor as long as he has a way of passing the same parameters (e.g. they are constant or calculated from available values).
In my opinion, this pretty much makes Crockford's solution useless. Since the "privacy" is easily broken the downsides of his solution (reduced readability & maintainability, decreased performance, increased memory) makes the "no privacy" prototype based method the better choice.
I do usually use leading underscores to mark __private and _protected methods and fields (Perl style), but the idea of having privacy in JavaScript just shows how it's a misunderstood language.
Therefore I disagree with Crockford except for his first sentence.
So how do you get real privacy in JS? Put everything that is required to be private on the server side and use JS to do AJAX calls.
The apotheosis of the Module Pattern: The Revealing Module Pattern
A neat little extension to a very robust pattern.
If you want the full range of public and private functions with the ability for public functions to access private functions, layout code for an object like this:
function MyObject(arg1, arg2, ...) {
//constructor code using constructor arguments...
//create/access public variables as
// this.var1 = foo;
//private variables
var v1;
var v2;
//private functions
function privateOne() {
}
function privateTwon() {
}
//public functions
MyObject.prototype.publicOne = function () {
};
MyObject.prototype.publicTwo = function () {
};
}
var TestClass = function( ) {
var privateProperty = 42;
function privateMethod( ) {
alert( "privateMethod, " + privateProperty );
}
this.public = {
constructor: TestClass,
publicProperty: 88,
publicMethod: function( ) {
alert( "publicMethod" );
privateMethod( );
}
};
};
TestClass.prototype = new TestClass( ).public;
var myTestClass = new TestClass( );
alert( myTestClass.publicProperty );
myTestClass.publicMethod( );
alert( myTestClass.privateMethod || "no privateMethod" );
Similar to georgebrock but a little less verbose (IMHO)
Any problems with doing it this way? (I haven't seen it anywhere)
edit: I realised this is kinda useless since every independent instantiation has its own copy of the public methods, thus undermining the use of the prototype.
Here's what i enjoyed the most so far regarding private/public methods/members and instantiation in javascript:
here is the article: http://www.sefol.com/?p=1090
and here is the example:
var Person = (function () {
//Immediately returns an anonymous function which builds our modules
return function (name, location) {
alert("createPerson called with " + name);
var localPrivateVar = name;
var localPublicVar = "A public variable";
var localPublicFunction = function () {
alert("PUBLIC Func called, private var is :" + localPrivateVar)
};
var localPrivateFunction = function () {
alert("PRIVATE Func called ")
};
var setName = function (name) {
localPrivateVar = name;
}
return {
publicVar: localPublicVar,
location: location,
publicFunction: localPublicFunction,
setName: setName
}
}
})();
//Request a Person instance - should print "createPerson called with ben"
var x = Person("ben", "germany");
//Request a Person instance - should print "createPerson called with candide"
var y = Person("candide", "belgium");
//Prints "ben"
x.publicFunction();
//Prints "candide"
y.publicFunction();
//Now call a public function which sets the value of a private variable in the x instance
x.setName("Ben 2");
//Shouldn't have changed this : prints "candide"
y.publicFunction();
//Should have changed this : prints "Ben 2"
x.publicFunction();
JSFiddle: http://jsfiddle.net/northkildonan/kopj3dt3/1/
The module pattern is right in most cases. But if you have thousands of instances, classes save memory. If saving memory is a concern and your objects contain a small amount of private data, but have a lot of public functions, then you'll want all public functions to live in the .prototype to save memory.
This is what I came up with:
var MyClass = (function () {
var secret = {}; // You can only getPriv() if you know this
function MyClass() {
var that = this, priv = {
foo: 0 // ... and other private values
};
that.getPriv = function (proof) {
return (proof === secret) && priv;
};
}
MyClass.prototype.inc = function () {
var priv = this.getPriv(secret);
priv.foo += 1;
return priv.foo;
};
return MyClass;
}());
var x = new MyClass();
x.inc(); // 1
x.inc(); // 2
The object priv contains private properties. It is accessible through the public function getPriv(), but this function returns false unless you pass it the secret, and this is only known inside the main closure.
What about this?
var Restaurant = (function() {
var _id = 0;
var privateVars = [];
function Restaurant(name) {
this.id = ++_id;
this.name = name;
privateVars[this.id] = {
cooked: []
};
}
Restaurant.prototype.cook = function (food) {
privateVars[this.id].cooked.push(food);
}
return Restaurant;
})();
Private variable lookup is impossible outside of the scope of the immediate function.
There is no duplication of functions, saving memory.
The downside is that the lookup of private variables is clunky privateVars[this.id].cooked is ridiculous to type. There is also an extra "id" variable.
Wrap all code in Anonymous Function: Then , all functions will be private ,ONLY functions attached to window object :
(function(w,nameSpacePrivate){
w.Person=function(name){
this.name=name;
return this;
};
w.Person.prototype.profilePublic=function(){
return nameSpacePrivate.profile.call(this);
};
nameSpacePrivate.profile=function(){
return 'My name is '+this.name;
};
})(window,{});
Use this :
var abdennour=new Person('Abdennour');
abdennour.profilePublic();
FIDDLE
I prefer to store private data in an associated WeakMap. This allows you to keep your public methods on the prototype where they belong. This seems to be the most efficient way to handle this problem for large numbers of objects.
const data = new WeakMap();
function Foo(value) {
data.set(this, {value});
}
// public method accessing private value
Foo.prototype.accessValue = function() {
return data.get(this).value;
}
// private 'method' accessing private value
function accessValue(foo) {
return data.get(foo).value;
}
export {Foo};
2021 HERE!
This polyfill effectively hides your private properties and methods returning undefined when you try to read your private property and a TypeError when you try to execute your private method thus effectively making them both PRIVATE to the outside but giving you access to them by using your public methods.
If you check it you will see it is very easy to implement. For the most part you don't need to do anything quirky like using Proxy objects, underscore functions (_myprivate), getters or setters. None of that. The only thing required is to place in your constructor that like snippet of code that is aimed to let you expose your public interface to the outside world.
((self) => ({
pubProp: self.pubProp,
// More public properties to export HERE
// ...
pubMethod: self.pubMethod.bind(self)
// More public mehods to export HERE
// Be sure bind each of them to self!!!
// ...
}))(self);
The above code is where the magic happens. It is an IIFE that returns an object with just the properties and methods you want to exposed and bound to the context of the object that was first instantiated.
You can still access your hidden properties and methods but only through your public methods just the way OOP should do.
Consider that part of the code as your module.exports
BTW, this is without using the latest ECMAScript 2022 # addition to the language.
'use strict';
class MyClass {
constructor(pubProp) {
let self = this;
self.pubProp = pubProp;
self.privProp = "I'm a private property!";
return ((self) => ({
pubProp: self.pubProp,
// More public properties to export HERE
// ...
pubMethod: self.pubMethod.bind(self)
// More public mehods to export HERE
// Be sure to bind each of them to self!!!
// ...
}))(self);
}
pubMethod() {
console.log("I'm a public method!");
console.log(this.pubProp);
return this.privMethod();
}
privMethod() {
console.log("I'm a private method!");
return this.privProp
}
}
const myObj = new MyClass("I'm a public property!");
console.log("***DUMPING MY NEW INSTANCE***");
console.dir(myObj);
console.log("");
console.log("***TESTING ACCESS TO PUBLIC PROPERTIES***");
console.log(myObj.pubProp);
console.log("");
console.log("***TESTING ACCESS TO PRIVATE PROPERTIES***");
console.log(myObj.privProp);
console.log("");
console.log("***TESTING ACCESS TO PUBLIC METHODS***");
console.log("1. pubMethod access pubProp ");
console.log("2. pubMethod calls privMethod");
console.log("3. privMethod access privProp");
console.log("")
console.log(myObj.pubMethod());
console.log("");
console.log("***TESTING ACCESS TO PRIVATE METHODS***");
console.log(myObj.privMethod());
Check my gist
Private functions cannot access the public variables using module pattern
Since everybody was posting here his own code, I'm gonna do that too...
I like Crockford because he introduced real object oriented patterns in Javascript. But he also came up with a new misunderstanding, the "that" one.
So why is he using "that = this"? It has nothing to do with private functions at all. It has to do with inner functions!
Because according to Crockford this is buggy code:
Function Foo( ) {
this.bar = 0;
var foobar=function( ) {
alert(this.bar);
}
}
So he suggested doing this:
Function Foo( ) {
this.bar = 0;
that = this;
var foobar=function( ) {
alert(that.bar);
}
}
So as I said, I'm quite sure that Crockford was wrong his explanation about that and this (but his code is certainly correct). Or was he just fooling the Javascript world, to know who is copying his code? I dunno...I'm no browser geek ;D
EDIT
Ah, that's what is all about: What does 'var that = this;' mean in JavaScript?
So Crockie was really wrong with his explanation....but right with his code, so he's still a great guy. :))
In general I added the private Object _ temporarily to the object.
You have to open the privacy exlipcitly in the "Power-constructor" for the method.
If you call the method from the prototype, you will
be able to overwrite the prototype-method
Make a public method accessible in the "Power-constructor": (ctx is the object context)
ctx.test = GD.Fabric.open('test', GD.Test.prototype, ctx, _); // is a private object
Now I have this openPrivacy:
GD.Fabric.openPrivacy = function(func, clss, ctx, _) {
return function() {
ctx._ = _;
var res = clss[func].apply(ctx, arguments);
ctx._ = null;
return res;
};
};
This is what I worked out:
Needs one class of sugar code that you can find here. Also supports protected, inheritance, virtual, static stuff...
;( function class_Restaurant( namespace )
{
'use strict';
if( namespace[ "Restaurant" ] ) return // protect against double inclusions
namespace.Restaurant = Restaurant
var Static = TidBits.OoJs.setupClass( namespace, "Restaurant" )
// constructor
//
function Restaurant()
{
this.toilets = 3
this.Private( private_stuff )
return this.Public( buy_food, use_restroom )
}
function private_stuff(){ console.log( "There are", this.toilets, "toilets available") }
function buy_food (){ return "food" }
function use_restroom (){ this.private_stuff() }
})( window )
var chinese = new Restaurant
console.log( chinese.buy_food() ); // output: food
console.log( chinese.use_restroom() ); // output: There are 3 toilets available
console.log( chinese.toilets ); // output: undefined
console.log( chinese.private_stuff() ); // output: undefined
// and throws: TypeError: Object #<Restaurant> has no method 'private_stuff'
Class({
Namespace:ABC,
Name:"ClassL2",
Bases:[ABC.ClassTop],
Private:{
m_var:2
},
Protected:{
proval:2,
fight:Property(function(){
this.m_var--;
console.log("ClassL2::fight (m_var)" +this.m_var);
},[Property.Type.Virtual])
},
Public:{
Fight:function(){
console.log("ClassL2::Fight (m_var)"+this.m_var);
this.fight();
}
}
});
https://github.com/nooning/JSClass
I have created a new tool to allow you to have true private methods on the prototype
https://github.com/TremayneChrist/ProtectJS
Example:
var MyObject = (function () {
// Create the object
function MyObject() {}
// Add methods to the prototype
MyObject.prototype = {
// This is our public method
public: function () {
console.log('PUBLIC method has been called');
},
// This is our private method, using (_)
_private: function () {
console.log('PRIVATE method has been called');
}
}
return protect(MyObject);
})();
// Create an instance of the object
var mo = new MyObject();
// Call its methods
mo.public(); // Pass
mo._private(); // Fail
You have to put a closure around your actual constructor-function, where you can define your private methods.
To change data of the instances through these private methods, you have to give them "this" with them, either as an function argument or by calling this function with .apply(this) :
var Restaurant = (function(){
var private_buy_food = function(that){
that.data.soldFood = true;
}
var private_take_a_shit = function(){
this.data.isdirty = true;
}
// New Closure
function restaurant()
{
this.data = {
isdirty : false,
soldFood: false,
};
}
restaurant.prototype.buy_food = function()
{
private_buy_food(this);
}
restaurant.prototype.use_restroom = function()
{
private_take_a_shit.call(this);
}
return restaurant;
})()
// TEST:
var McDonalds = new Restaurant();
McDonalds.buy_food();
McDonalds.use_restroom();
console.log(McDonalds);
console.log(McDonalds.__proto__);
I know it's a bit too late but how about this?
var obj = function(){
var pr = "private";
var prt = Object.getPrototypeOf(this);
if(!prt.hasOwnProperty("showPrivate")){
prt.showPrivate = function(){
console.log(pr);
}
}
}
var i = new obj();
i.showPrivate();
console.log(i.hasOwnProperty("pr"));

Categories