How to declare private variables and private methods in es6 class [duplicate] - javascript

This question already has answers here:
How to work with private variables in ES6? [duplicate]
(4 answers)
Closed 7 years ago.
in es5 we use constructor function
function Person(name,gender){
var initial =""; // we use var key word to make variable private
function getNameWithInitial(){ // this is the private method to get name with initial
console.log(this);
initial = this.gender ==="male"?"Mr. ":"Mrs. ";
return initial + this.name;
}
this.name = name;
this.gender = gender;
this.getName = function(){
return getNameWithInitial.call(this);
}
}
var manas = new Person("Manas","male");
console.log(manas.getName());
My question is how to declare a private variable and private method in es6 class

One way to achieve this is using another ES2015 feature known as modules.
You may already be familiar with AMD modules, or commonJS modules (used by Nodejs). Well ES6 / ES2015 brings a standard for JS - we'll call them ES6 modules but they are part of the JS language now. Once you have modules, you have the ability to do information hiding for both private functions and object variables. Bear in mind, only what you "export" is visible to client calling code.
Lets work through your example code. Here is a first cut:
person.js
const getNameWithInitial = function () {
let initial = this._gender === 'male' ?
'Mr. ' :
'Mrs. ';
return initial + this._name;
}
export class Person {
constructor(name, gender) {
this._name = name;
this._gender = gender;
}
get name() {
return getNameWithInitial.call(this);
}
}
}
client.js
import {Person} from './person';
const manas = new Person('Manas', 'male');
console.log(manas.name); // this calls what was your getName function
Now, the getNameWithInitial function is effectively private, as it is not exported, so client.js cannot see it.
However, we still have a problem for the Person class, since this is exported. At the moment you can just walk up to manas object and do:
manas._name = 'Joe'
With properties like _name, we can combine modules and symbols. This is a powerful yet lightweight information hiding technique available with ES6+/ES2015.
Symbol is a new built-in type. Every new Symbol value is unique. Hence can be used as a key on an object.
If the client calling code doesn't know the symbol used to access that key, they can't get hold of it since the symbol is not exported.
Let's see our modified code to make use of symbols and modules to hide Class attributes.
person.js
const s_name = Symbol();
const s_gender = Symbol();
const getNameWithInitial = function () {
let initial = this[s_gender] === 'male' ?
'Mr. ' :
'Mrs. ';
return initial + this[s_name];
}
export class Person {
constructor(name, gender) {
this[s_name] = name;
this[s_gender] = gender;
}
get name() {
return getNameWithInitial.call(this);
}
}
So, now a client cannot just do:
manas._name = 'Joe'
because _name is not being used as the key for the name value.
However, symbols are exposed via reflection features such as Object.getOwnPropertySymbols so be aware they are not "completely' private using this technique.
import {Person} from './person';
const manas = new Person('Manas', 'male');
const vals = Object.getOwnPropertySymbols(manas);
manas[vals[0]] = 'Joanne';
manas[vals[1]] = 'female';
Takeaway message - Modules in general are a great way to hide something because if not exported then not available for use outside the module, and used with privately stored Symbols to act as the keys, then class attributes too can become hidden (but not strictly private). Using modules today is available with build tools eg. webpack / browserify and babel.

If you would like an analogue to the ES5 solution, it's quite simple; the constructor simply becomes what holds the closure, and you add any methods/objects which should remember the private state in there.
Prototyped methods have no access to the closure of the initial constructor, without using some privileged getters:
class Person {
constructor ({ name, age, deepDarkSecret }) {
const bribe = () => console.log(`Give me money, or everybody will know about ${ redactRandom(deepDarkSecret) }`);
Object.assign(this, { name, age }); // assigning publicly accessible values
Object.assign(this, { bribe }); // assign "privileged" methods (functions with closure-reference to initial values)
}
recallSecret () {
console.log("I'm just a prototyped method, so I know nothing about any secret, unless I use a privileged function...");
this.bribe();
}
}
If you look at what this nets you, you'll note that it's really not much different than your example (just using "cleaner" bells and whistles; especially when adding prototype/static methods). It's still prototype underneath.
If you have the luxury of using any kind of module/export (ES6 being the ideal), then with one other data-type, you can have true privacy and not have to clean up after yourself.
It's a little hackey-looking. It'll probably get less ugly, and hopefully be the basis for something cleaner, in the future, but if you want instance-based, private access, even for prototyped methods, then make one WeakMap, inside of the module that you're exporting your class from.
Use this as your key.
Rather than making privileged functions which have closure access, now all prototype methods have closure access to the weakmap...
...the downside being that any time you want private variables, you have to look them up in the WeakMap rather than pulling them off of / out of this.
const personalBaggage = new WeakMap();
class Person {
constructor ({ name, age, darkestMoment }) {
const privates = { name, age, darkestMoment };
personalBaggage.add(this, privates);
}
recallDarkestHour () {
const { darkestMoment } = personalBaggage.get(this);
console.log(darkestMoment);
}
}
export default Person;
As long as you aren't losing the reference inside of this, this should just work.
Unlike using Symbol, you can't get a reference to the private object, no matter how hard you try.
If you know the symbols on the object, you can look up the properties using the symbols.
And getting the list of symbols on any object is just a function call away.
Symbol isn't about keeping things private; it's about keeping things safe from naming collisions, and defining common symbols that can be used on any object/function, but won't be picked up in loops, won't be called or overwritten accidentally, et cetera.
Storing the private bag of data in a weakmap with this as a key gives you access to a completely hidden dataset, which is totally unaccessible outside of that module.
What's better, the key/value in weakmaps don't prevent the GC from cleaning them up.
Normally, if they were left in an array, they'd stay there. If the last place an object is used is as a key in a weakmap, then it gets collected and the weakmap value is erased automatically (in native ES6; the memory bonuses can't be polyfilled, but the object can).

here is a really good post on the subject. I didn't know much about doing this in ES6 before your question but after reviewing this it looks really cool. So you create a symbol that is indexed to the function.
here is the code straight from their sit.
var Person = (function() {
var nameSymbol = Symbol('name');
function Person(name) {
this[nameSymbol] = name;
}
Person.prototype.getName = function() {
return this[nameSymbol];
};
return Person;
}());
var p = new Person('John');
Private properties in JavaScript

You may accomplish it using Symbol.
const _name = Symbol();
class Person {
constructor(name) {
this[_name] = name;
}
}
const person = new Person('John');
alert(person.name);
// => undefined
Reference
Documentation

Related

How do I write 'this' less often?

Using ES6 classes is great and all, but I find myself using this.variable everywhere, and it is always referring to my class. Is there a way to have implied globals within my class be implied this.variable instead? So if I write 'width' it will be defaulted to this.width instead of an implied global?
Or if there are some best practices that I might not be aware of to cut down on my 'this' addiction I'd love to read that too. In the file I'm currently working on there are about half as many this keywords as there are lines of code...
Using constructor functions / classes and this is just one way to use JavaScript. JavaScript is a multi-paradigm language and yes, it's entirely possible to use it largely without using this. One way is via closures.
Consider this class example:
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
this.things = [];
}
sayHello() {
console.log(`Hi, I'm ${this.first} ${this.last}`);
}
grabThing(thing) {
this.things.push(thing);
}
}
const p1 = new Person("Joe", "Bloggs");
p1.sayHello();
p1.grabThing("thing1");
console.log(p1.first + "'s things: " + p1.things.join(", "));
const p2 = new Person("Suresh", "Kumar");
p2.sayHello();
p2.grabThing("thing2");
p2.grabThing("thing3");
console.log(p2.first + "'s things: " + p2.things.join(", "));
Now, consider this approach with closures:
function createPerson(first, last) {
const things = [];
return {
sayHello() {
console.log(`Hi, I'm ${first} ${last}`);
},
grabThing(thing) {
things.push(thing);
},
get things() {
return things;
},
get first() {
return first;
},
get last() {
return last;
}
};
}
const p1 = createPerson("Joe", "Bloggs");
p1.sayHello();
p1.grabThing("thing1");
console.log(p1.first + "'s things: " + p1.things.join(", "));
const p2 = createPerson("Suresh", "Kumar");
p2.sayHello();
p2.grabThing("thing2");
p2.grabThing("thing3");
console.log(p2.first + "'s things: " + p2.things.join(", "));
Notice how we just use the first and last parameters provided to the createPerson function directly in sayHello, and we just declare things as a local constant which grabThing closes over. In that example, we also provide getters for the various bits of information (first, last, things) so they can be used from the object we return, but if there were information we wanted to keep private, we could leave out the getter. (And some prefer to make those explicitly functions rather than getters.)
One downside to this approach is that there are separate function objects for sayHello, grabThing, the getters, etc., for each object created by createPerson, while in the class example, there's only one sayHello function object, which is shared amongst Person objects via prototypical inheritance. On the one hand, creating additional sayHello function objects seems wasteful; but modern JavaScript engines reuse the underlying function code even though there are distinct sayHello objects, and objects are fairly cheap in our modern world.
Upsides are the easy way to have private information and not having to use and manage this.
Douglas Crockford (amongst others) promotes this approach, if you want to learn more about it. (Note that in his writing, Crockford sometimes fails to clearly distinguish between fact and his opinion — and boy does he have opinions — but his writing is well worth reading regardless.)
(I'm not advocating either class or non-class, just noting there are options.)
I know this isn't a recommended practice, but a with statement is sortof what OP asks for.
with allows parsing an object, using the attributes as variables within the statement:
var MyClass = /** #class */ (function() {
function MyClass(name, age) {
this.name = name;
this.age = age;
}
MyClass.prototype.whoami = function() {
with(this) {
console.log(name, age);
}
};
return MyClass;
}());
var c = new MyClass("bob", 123);
c.whoami();
There is the issue that with is disabled in strict mode though, meaning that there are some contexts where it simply won't work.
ES6 classes is one such context, so if OP want's to use ES6 classes, then with is out.
Looking back at this old question the answer has become obvious with the release of hooks, just don't write class components and write function components instead :)

Explanation of "Functional Pattern" from the book "JavaScript: The Good parts"

I am learning JS these days and I am unable to assimilate this Functional Pattern on page 52 of the book.
Functional
One weakness of the inheritance patterns we have seen so far is that we get no privacy.
All properties of an object are visible. We get no private variables and no
private methods. Sometimes that doesn’t matter, but sometimes it matters a lot. In frustration, some uninformed programmers have adopted a pattern of pretend
privacy. If they have a property that they wish to make private, they give it an odd looking name, with the hope that other users of the code will pretend that they cannot
see the odd looking members. Fortunately, we have a much better alternative in
an application of the module pattern.
We start by making a function that will produce objects. We will give it a name that
starts with a lowercase letter because it will not require the use of the new prefix. The
function contains four steps:
It creates a new object. There are lots of ways to make an object. It can make an
object literal, or it can call a constructor function with the new prefix, or it can
use the Object.beget method to make a new instance from an existing object, or
it can call any function that returns an object.
It optionally defines private instance variables and methods. These are just ordinary
vars of the function.
It augments that new object with methods. Those methods will have privileged
access to the parameters and the vars defined in the second step.
It returns that new object.
Here is a pseudocode template for a functional constructor (boldface text added for
emphasis):
var constructor = function (spec, my) {
var that, //other private instance variables;
my = my || {};
// Add shared variables and functions to my
that = a new object;
// Add privileged methods to that
return that;
}
The spec object contains all of the information that the constructor needs to make an
instance. The contents of the spec could be copied into private variables or transformed
by other functions. Or the methods can access information from spec as they
need it. (A simplification is to replace spec with a single value. This is useful when
the object being constructed does not need a whole spec object.)
Can anyone explain, what's going on there (in layman terms) and where such a pattern is useful?
Note: While the book you refer to is indeed an immensely helpful book, its quite ancient. Some of the "good" (and even "bad") parts have been replaced by even better alternatives and features in newest versions of JavaScript.
One weakness of the inheritance patterns we have seen so far is that
we get no privacy. All properties of an object are visible. We get no
private variables and no private methods.
A Javascript object has "properties", which can be other objects, or functions. Consider:
var obj = {a: 1, do: function(){console.log('done');} }
Nothing is stopping you from calling obj.a = 5, or obj.done().
But one might counter that that's not a good way of creating objects. We better have a prototype or class from which we can create new instances:
function Animal(name) {
this._name = name;
}
Animal.prototype.print = function(){console.log(this._name)};
or in more recent JavaScript versions:
class Animal {
constructor(name){
this._name = name;
}
print(){
console.log(this._name);
}
}
In frustration, some uninformed programmers have adopted a pattern of
pretend privacy. If they have a property that they wish to make
private, they give it an odd looking name, with the hope that other
users of the code will pretend that they cannot see the odd looking
members.
This is a comment on above code. When declaring JavaScript classes or functions, there is no official, standard, "fool proof AND syntactically elegant" way of keeping instance variables private. That is, an easy, clean way of declaring a variable that is only accessible to methods defined in that class or prototype (See this answer). So, people follow some agreed upon patterns, one of which is prefixing the variables names with a _. This actually provides no privacy to internal variables of a class instance.
With advent of the module system, one could write JavaScript code in a separate file/container and choose to make only specific objects visible to the outside world. A CommonJS example:
Animal.js:
const props = new WeakMap();
class Animal {
constructor(name){
props.set(this,{});
props.get(this).name = name;
}
set age(n){
props.get(this).age = age;
}
function print(){
console.log(props.get(this));
}
}
module.exports = Animal;
Above is one of the ways to declare a class with private properties not accessible from outside unless intentionally leaked. Notice how the object props is not exported to outside world.
Fortunately, we have a much better alternative in an application of
the module pattern.
You might think that the above module code is actually what this text means, but the above implementation is a newer version using latest features. The old school way the points in text illustrate is to expose an object creator (a.k.a factory) function. Everything declared inside the creator function and outside the created object is private by design:
function createAnimal(name){
var age = 0;
var animal = {};
animal.setAge = function(a){age = a;};
animal.getName = function(){return name;};
animal.print = function(){console.log({'name':name,'age':age});};
}
Inheritance here is a call to super creator and modifying the super instance:
function createDog(name, color){
var breed = 'unknown';
var dog = createAnimal(name);
dog.setBreed = function(b){breed = b;};
}
Essentially, the idea is to hide private variables within a closure. The variables being closed over are the (not shown) "other private instance variables", and the methods that actually are closing over these variables are the (also not shown) "privileged methods".
For example, take this function:
var createBoard = function (rows, cols) {
var cells = [];
var board = {};
for (var i = 0; i < rows; i++) {
cells[i] = [];
for (var j = 0; j < cols; j++) {
cells[i][j] = { player: null };
}
}
board.play = function (row, col, player) {
if (cells[row][col].player === null) {
cells[row][col].player = player;
}
};
board.getPlayer = function (row, col) {
return cells[row][col].player;
};
return board;
};
And let's assume we call this function to create an 8x8 gameboard:
var board = createBoard(8,8);
board.play(1,2,"Player1");
console.log(board.getPlayer(1,2));
board.play(1,2,"Player2"); // Doesn't actually do anything
// Note this code has no direct access to cells[][] except via the two
// methods we defined on the board object.
In this case, we return a board object. The board internally has access to a cells array, but we don't let anyone modify this except using our two methods, play (which occupies a board space only if it was previously unoccupied) and a getPlayer method that returns the player at a given space. Cells[][] is totally hidden to the user of this code - they couldn't cheat by changing our cell array directly.
JavaScript is an object-based language based on prototypes, rather than being class-based. 1
Compare that with Object-Oriented languages based on classes like PHP, Java, etc. In those languages, a class can be defined and member variables can have various visibility inside and outside the class. For instance, PHP has visibility set on three levels: public, protected or private.
Class members declared public can be accessed everywhere. Members declared protected can be accessed only within the class itself and by inherited classes. Members declared as private may only be accessed by the class that defines the member.2
class MyClass {
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello() {
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
But in JavaScript, we don't really have such a concept of private variables (in the same sense). That is what the author is talking about when describing the module pattern.
So if we wanted to make an analagous construct in Javascript, we could make something like this:
var MyClass = function (rows, cols) {
//this could be used in prototype functions
var private = 'Private';
var members = {
public: 'Public';
getHello: function() {
return 'MyClass _ ' + private;
}
};
return members;
};

Classes & 'access modifiers' in javascript

I am trying to understand how "classes" work in ES5 and how I can apply my knowledge of traditional, typed object oriented languages like Java to javascript.
In the following code sample I have commented with my questions.
var MyClass = (function () {
// [What am I?] A private variable?
var myVariable1
// Constructor.
function MyClass() {
// Essentially a public variable.
this.myVariable2 = 0;
}
// Public method returning myVariable1.
MyClass.prototype.myMethod1 = function () {
return myVariable1;
};
// Public method returning public variable.
MyClass.prototype.myMethod2 = function () {
return this.myVariable2;
};
// [What am I?] A private method?
function myMethod3 () {
return 0;
}
return MyClass;
}());
I am mostly wondering about the "private" stuff. Like, what happens if I have multiple instances of this class? Can they interfere with each others private variables and functions?
First I'll address this bit:
...and how I can apply my knowledge of traditional, typed object oriented languages like Java to javascript.
You can frequently get away with thinking of JavaScript as being a bit like Java/C#/etc., but if you do:
It'll bite you at some point, because JavaScript is not like Java/C#/etc., it is fundamentally different even though it has some trappings that make it look similar;
and
You'll miss out on the true power of JavaScript by not knowing how to use its fundamentally-different nature.
How do I know? I did exactly that, came from a Java (and even C++) background and assumed JavaScript was similar, and got bitten, and missed out (initially). :-)
That's not remotely meant as any form of criticism, it's just a word to the wise. Try to learn in depth how JavaScript prototypical inheritance and closures work, and you'll find that the way you solve problems will be slightly different than the way you would in Java/C#/etc.
In Old Environments
Answers to your direct queries inline in this code block, but in 2022 I added a bit below ("In Modern Environments") to address the new modern features recently added to JavaScript to directly address these use cases in different ways.
var MyClass = (function () {
// [What am I?] A private variable?
// ==> A private *class* variable (static variable). Not instance-specific.
var myVariable1
// Constructor.
function MyClass() {
// Essentially a public variable.
// ==> A public field/property/variable, choose your terminology. :-)
// ==> The Java spec calls them both fields and variables (oddly).
// ==> In JavaScript, they're called properties.
this.myVariable2 = 0;
}
// Public method returning myVariable1.
// ==> Correct, but note that myVariable1 is shared across all instances
MyClass.prototype.myMethod1 = function () {
return myVariable1;
};
// Public method returning public variable.
// ==> Yes, note that this one is returning an instance-specific field/property/variable
MyClass.prototype.myMethod2 = function () {
return this.myVariable2;
};
// [What am I?] A private method?
// ==> A private *class* method (static method), yes.
function myMethod3 () {
return 0;
}
return MyClass;
}());
I am mostly wondering about the "private" stuff. Like, what happens if I have multiple instances of this class? Can they interfere with each others private variables and functions?
Yes, as I mentioned in the comments, they're class-wide. If you wanted to have a private "instance field", you'd have to declare it within your constructor, and create any functions that needed to have access to it within the constructor so that they closed over it:
function MyClass(arg) {
var privateInstanceInfo = arg; // We could also just use arg directly
this.accessThePrivateInstanceInfo = function() {
return privateInstanceInfo * 42;
};
}
MyClass.prototype.useOnlyPublicInfo = function() {
// This cannot access `privateInstanceInfo` directly.
// It *can* access the function `accessThePrivateInstanceInfo`
// because that's public:
return accessThePrivateInstanceInfo();
};
var c = new MyClass(2);
console.log(c.useOnlyPublicInfo()); // 84
This is all down to a concept called closures, which is outlined in detail in this question and its answers: How do JavaScript closures work? I'll also reference my article from several years ago Closures are not complicated, which while it uses some older terms for things compared to the latest specification, still describes the concepts just fine.
The inline-invoked function (IIFE) you've used as a wrapper creates a single execution context that all of the functions within it close over. That means they have live access to the variables and functions defined within that context, even after the function returns. Since you only call it once, there's only one context, and so only one myVariable1 and myMethod3.
In my example creating private instance information, we use the fact that a new context is created for each call to the constructor. That context isn't shared with anything else, and so becomes instance-specific.
There's a way to get near-private instance properties without having to define functions in the constructor, which is to use a randomly-selected name:
function makeRandomName() {
var str = "";
while (str.length < 10) {
str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
}
return "__" + str;
}
var MyClass = (function() {
var pseudoPrivatePropName = makeRandomName();
function MyClass() {
this[pseudoPrivatePropName] = 42;
}
// ....
return MyClass;
})();
The code inside the IIFE knows the name of the property, the code outside of it doesn't. Now, malicious code could still find the property, but it's become much more challenging, particularly if you have more than one. (And if you have more than one, you need a better name allocator than the one above.) (Details in this very-outdated article in my blog.)
In ES2015 (ES6) you could use
var pseudoPrivatePropName = Symbol();
...instead of having a name allocator, but it doesn't make the property any more private.
In Modern Environments
In modern environments though, you can use new features that have been added to JavaScript for the ES2022 specification:
Class Public Instance Fields & Private Instance Fields
Private instance methods and accessors
Static class fields and private static methods
Here's how you might right MyClass using those features and ES2015's class syntax:
class MyClass {
// Static class field (class-wide, not instance-specific)
static myVariable1;
// Instance class field (property) (instance-specific)
myVariable2 = 0;
// Private class field (instance-specific)
#privateInstanceInfo;
// Private static class field (class-wide, not instance-specific)
static #privateStaticInfo;
// Constructor for the class
constructor(arg) {
this.#privateInstanceInfo = arg;
}
// Public instance method returning static member
myMethod1() {
// Note that `MyClass.myVariable1` is shared across all instances
return MyClass.myVariable1;
}
// Public instance method return instance field (property) value
myMethod2() {
return this.myVariable2;
}
// Public instance method accessing the private field; all methods declared
// for the class can access it, not just this one
accessThePrivateInstanceInfo() {
return this.#privateInstanceInfo * 42;
}
// Private instance method
#myMethod3() {
return 0;
}
// Static method
static myStaticMethod() {
return this.#getPrivateStaticInfo(); // Or `MyClass.#getPrivateStaticInfo();`
}
// Private static method
static #getPrivateStaticInfo() {
return this.#privateStaticInfo; // Or `MyClass.#privateStaticInfo`
}
}
On those last two, the static method and the private static method, note that usually this during the call will refer to the class constructor itself (MyClass), because usually you're calling static members by doing MyClass.myStaticMethod(). But as usual with this, that's not necessarily true; if you did const f = MyClass.myStaticMethod; f();, this during the call wouldn't refer to MyClass. Using this in static methods to refer to the constructor is friendly to subclasses (because a subclass constructor's prototype is its superclass constructor; details here), but does mean you have to deal with the usual caveats around this.
Use # for private, and _ for protected.

Javascript object oriented programming techniques, what is this called?

There seems to be quite a few techniques out there for creating client side objects. What I find really confusing is determining what each technique is called. I've used prototype before
MyObject.prototype.someMethod = function (e, a) {
.....
};
But I've also seen objects created in different like this
MyObject.someMethod = function () {
....
}
What is the second techinque called and why would one use one over the other?
The first example is analogues to defining methods on a class. Every instance of the class uses the same code; this in such a method points to the instance on which the method was invoked.
The second is analogous to defining a static method on a class. You invoke the method like
MyObject.someMethod();
It doesn't make sense to invoke the method on an instance.
I guess you could call the first "prototype methods" and the second "constructor/class methods".
If you are comfortable using classical OO terminology when talking about javascript, which is somewhat awkward as Javascript uses prototypal inheritance, you can call the the first "instance methods" and the second "static methods".
The simplest answer is that using the prototype keyword to define a method on an object will allow that method to be used on all objects which inherit from it.
There are no classes in JavaScript, but you can emulate inheritance through the use of the prototype object (property).
myObject.prototype.method will add a "method" to ALL objects derived from myObject (you can do this to jQuery after jQuery has loaded -- $.prototype.method [$.fn.method] would add a method to all jQuery objects regardless of when they are/were created).
myObject.method will only add a "method" to myObject as it was at the time that line of code was executed (a static method). Any myObject invoked before this line executes will not have access to "method".
Javascript uses what's called Prototypical Inheritance to implement inheritance of traits. Consider the following example:
Superclass = function() {
//constructor code
}
Superclass.prototype.toString=function() {
return "Derp!";
}
Superclass.derp= function(){return 'herp!'}
var instance = new Superclass();
instance.toString();//valid
instance.derp();//fails
There are several things going on here.
First, before worrying about defining methods of objects, worry about the creation of objects.
So, there are several ways of creating objects. First, you can just create an inline object, out of the blue:
var obj = { property : "myProperty", func : function () {} };
You now have a brand new object.
You can extend that object by adding to it, after the fact.
obj.property02 = "myOtherProperty";
obj.otherFunc = function () { return this.property02; };
But the downfall of constructing inline objects is that all properties and methods are 100% public.
In order to deal with this, you can have a constructor function which creates and returns an object.
var MakeWallet = function (starting_amount, pin) {
var balance = 0,
wallet = {};
wallet.add = add_balance;
wallet.deduct = deduct_amount;
wallet.amount = check_balance;
return wallet;
function check_balance (pin) { /*...*/ }
function validate_pin (user_pin) { /*...*/ }
function add_balance (amount, pin) { /*...*/ }
function deduct_amount (amount, pin) { /*...*/ }
};
var myWallet = MakeWallet(1, 9274);
What do I get for my trouble?
ALL of the data is tamper-proof.
A user might still be able to rewrite wallet.deduct, but they won't actually get the real value of the pin, or get the amount in the wallet, or get any of the internal functions that I don't want them to have, including any internal security-numbers or entity/serial numbers I want to grant to track the wallet.
That's the benefit of building in this way.
Again, I can add methods and properties to the wallet, afterward:
myWallet.breakItOpen = function () { return this.balance; };
myWallet.stuffIt = function () { balance = 400000000; };
But neither of these things is actually going to have access to the variables or the functions inside of the original myWallet.
Only functions which existed at the time of creation will have access.
In other, more traditional creation-methods, you can use a class-like constructor function, using this.
function MakeWalletClass (starting_amount, pin) {
var balance = 0,
serial_and_pin = generate_serial() + "_" + pin;
this.balance = balance;
this.checkBalance = function () { return this.balance; };
}
var myWalletInstance = new MakeWalletClass(1, 1234);
But there's a problem:
myWalletInstance.balance is public.
Anybody can see it or change it.
Not good.
We could get around that by doing this:
function MakeWalletClass (starting_amount, pin) {
var balance = 0,
serial_and_pin = generate_serial() + "_" + pin;
this.checkBalance = function () { return balance; };
}
var myWalletInstance = new MakeWalletClass(1, 1234);
Now, this.checkBalance is reading the hidden balance variable, and not a publicly editable property.
Now, MakeWalletClass.prototype.
When you use the constructor pattern (ie: a function which adds properties to this and returns this, or doesn't return anything -- it returns this in the background -- and is called with the new keyword), adding prototype properties and methods will add properties and methods which are available to EVERY instance of the object you made.
So if your bank is called "The Bank of Bob", you could add:
MakeWalletClass.prototype.bankName = "The Bank of Bob";
Now every single instance of new MakeWalletClass(); will have a bankName property, and every one will be the exact-same value, and every one will be publicly available.
var yourWalletInstance = new MakeWalletClass(500, 2341);
yourWalletInstance.bankName; // "The Bank of Bob";
The prototype properties are even available on objects that you make before you add the property to the constructor function's prototype.
You can add prototype methods in the same way.
var myWalletInstance = new MakeWalletClass(1, 1234);
MakeWalletClass.prototype.getBalance = function () { return balance; };
myWalletInstance.getBalance(); // undefined;
Whoops!
It doesn't work.
Prototype functions have access ONLY to public properties (anything they can call with this.XXX).
So the upside of adding prototype properties is that they save a lot of memory.
If your program requires 3000 wallets, and you add a prototype function to the constructor, that function only exists 1 time in memory.
The downside of adding the prototype is that it can only do public things, so unless you want to make balance or pin public properties (hint: don't), prototypes are useless for private work.
So for those 3000 wallets, you need 3000 copies of any method that deals with balance or pin.
Now that you've got an understanding of all of that, and what prototype is for... the REAL difference between:
MakeWalletClass.prototype.say_bankName = function () { /*...*/ };
and
MakeWalletClass.say_bankName = function () { /*...*/ };
is that the prototype works on instances (wallet = new MakeWalletClass), and the method of MakeWalletClass doesn't -- it's only useful if you want a function attached to MakeWalletClass.
Maybe you want a function that returns the number of wallets made...

Private AND Static AND Inherited variables!? Or similar

I'm building a system, with similar details as this question: Can I have different copies of a static variable for each different type of inheriting class
Except it's in JavaScript!
I'm going to have a set of subclasses. Each subclass will have a lot of instances created of it during the life of the program. Each instance of a particular subclass will have different values, except for a file that is common to all. I don't want each instance to have a copy. I want it static (one copy for all). Each different subclass uses a different file though. I want each subclass to inherit the FACT that it HAS a file from a superclass.
EDIT: Quick Summary:
goal: create a class that is a constructor that
constructs the definition of a
subclass, allowing a variable:
- Appearing in every subclass
- Unique to a particular subclass
- Shared by all instances of a particular subclass (one copy for all)
Attempt at illustrating this in code:
var instance1ofSubclass1 = {
staticVar:"SAMEVAL_1", // For brevity I'm showing how staticVar is
// the same. It's notsupposed to be public.
uniqueVar:"adsfasdf"
};
var instance2ofSubclass1 = {
staticVar:"SAMEVAL_1",
uniqueVar:"zxbvczbxc"
};
var instance3ofSubclass1 = {
staticVar:"SAMEVAL_1",
uniqueVar:"qwrtytry"
};
var instance1ofSubclass2 = {
staticVar:"SAMEVAL_2", //<--notice the static var is different
// between subclasses
uniqueVar:"oipoiuu"
};
var instance2ofSubclass2 = {
staticVar:"SAMEVAL_2",
uniqueVar:"hljkhlj"
};
var instance3ofSubclass2 = {
staticVar:"SAMEVAL_2",
uniqueVar:"bnmbmbmnm"
};
My class definitions could go like this:
var subclass1 = (function () {
var staticVar = "SAMEVAL_1"
return function (unique) {
return {
uniqueVar:unique
};
};
}());
var subclass2 = (function () {
var staticVar = "SAMEVAL_2" //<-- different static variable
return function (unique) {
return {
uniqueVar:unique
};
};
}());
Now, I want to go a step further and make a superclass for these classes. That's where I'm stuck. I don't want to have a staticVar definition in every subclass. I want to get it from the superclass.
First of, the compiler will never be able to prevent you from forgetting something since there is no compiler. That's something we'll have to live without.
My suggestion for you would be to use prototyping for this. If the prototype of the superclass contains your variable, the same instance will be used for all the subclasses. And you wont have to repeat yourself in your subclass-files. Static and inherited, so to speak.
MySuperClass.prototype.myStaticVar = "giantFile";
The downside of this solution is that the variable won't really be private. On the other hand, do you really, really need it to be private?
The concept of privacy is a little funny anyhow. In C/C++ everything (private stuff too) can be accessed by pointer-magic. In C# you can use reflection to alter private variables. Nothing is ever really private. JavaScript is even funnier since the scripts in the browser can be altered by the end-user himself! In my opinion, hiding in plain sight is the way to go in this case. Name your variable appropriately (for example, add an underscore or two the beginning of it's name to signify "privacy").
if i'm reading this right, I had a similar issue that you did. Check this SO question that i posted a few weeks ago.
to take that a step further, my .add() method checks to see if the passed in namespace has a supr object attached to it, if not, then it appends the base object called supr to that namespace so that it can have easy access to the root.
I think I've figured it out.
Fiddle: http://jsfiddle.net/zXMaM/
The pattern I've created sends a class definition through another function (essentially the super class) that creates an additional closure for the necessary private static variables and at the same time augments the object created by the class passed in to access the private static variables.
It's hard to explain as this is new to me too, but hopefully between the code and my comments it is followable.
The "superclass" method:
var superClass = function (yourPrivateStaticVar, classDef) {
var privateStatic = yourPrivateStaticVar;
return function () { // return a new constructor (only invoked when a new
// instance is created!)
// run the constructor, grab the object it creates
var newObj = classDef();
// now, augment the object created (these vars/methods have no
// knowledge of the subclass!)
//add private vars/methods to the object
function getPrivStatic() {
return privateStatic;
}
var example_inherited_private_var;
//add public vars/methods to the object
newObj.getPrSt_directly = function () {
return privateStatic;
}
newObj.getPrSt_throughPrivateFunc = function () {
return getPrivStatic();
}
newObj.example_inherited_public_var = "something";
//return the augmented object (a new *instance* of the subclass)
return newObj;
};
};
Defining a "subclass":
//pass the definition of subclass1 through the superclass method and get it back
var subClass1 = superClass("yourChosenPrivateStaticValue", function () {
//private variables/methods go here
return { //this is the actual instance object
//public variables/methods go here
};
});
Again, the fiddle: http://jsfiddle.net/zXMaM/

Categories