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;
};
Related
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.
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
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...
What are the basic ways of defining reusable objects in Javascript? I say reusable to exclude singleton techniques, such as declaring a variable with object literal notation directly. I saw somewhere that Crockford defines four such ways in his book(s) but I would rather not have to buy a book for this short bit of information.
Here are the ways I'm familiar with:
Using this, and constructing with new (I think this is called classical?)
function Foo() {
var private = 3;
this.add = function(bar) { return private + bar; }
}
var myFoo = new Foo();
Using prototypes, which is similar
function Foo() {
var private = 3;
}
Foo.prototype.add = function(bar) { /* can't access private, correct? */ }
Returning a literal, not using this or new
function Foo() {
var private = 3;
var add = function(bar) { return private + bar; }
return {
add: add
};
}
var myFoo = Foo();
I can think of relatively minor variations on these that probably don't matter in any significant way. What styles am I missing? More importantly, what are the pros and cons of each? Is there a recommended one to stick to, or is it a matter of preference and a holy war?
Use the prototype. Returning specific objects from constructors makes them non-constructors, and assigning methods to this makes inheritance less convenient.
Returning an object literal
Pros:
If a person forgets new, they still get the object.
You can create truly private variables, since all methods of the object defined inside the constructor share its scope.
Cons:
It’s not a real constructor. Adding something to its prototype won’t change the returned objects, new or no new. new Foo() instanceof Foo would also result in false.
Using prototype
Pros:
You leave the constructor uncluttered.
This is the standard way of doing things in JavaScript, and all built-in constructors put their methods on their prototypes.
Inheritance becomes easier and more correct; you can (and should) use Object.create(ParentConstructor.prototype) instead of new ParentConstructor(), then call ParentConstructor from within Constructor. If you want to override a method, you’re able to do it on the prototype.
You can “modify” objects after they’ve already been created.
You can extend the prototypes of constructors you don’t have access to.
Cons:
It can get to be a bit too verbose, and if you want to change the function’s name, you have to change all of the functions added to the prototype, too. (Either that or define the prototype as one big object literal with a compatible property descriptor for constructor.)
They don’t share an instance-specific scope, so you can’t really have private variables.
Assigning to this.* in the constructor
Pros:
You can use closures and therefore private member variables.
Cons:
No duck typing; you can’t call a method right off of the prototype with any old object. For example, Array.prototype.slice.call(collectionLikeObject).
It's mostly a matter of preference. There's no one way to make Chicken Noodle soup, and uniform objects are the same way.
I don't use any of those 3, although they all work for their own purposes. I use a custom function called Object:deploy, and use it like this..
var a = { hey: 'hello' },
b = {}.deploy(a);
console.log(b.hey); // 'hello'
Using prototype is the best for most people because of automatic trickling.
function A() {};
A.prototype.hello = "Hey";
var a = new A();
console.log(a.hello); // 'Hey'
A.prototype.hello = "Hello";
console.log(a.hello); // 'Hello'
And contrary to popular belief, you can use private variables in prototype.
function Hello() {};
(function () {
var greeting = "Hello";
Hello.prototype.greet = function () { return greeting };
}).apply(this);
But even though that's possible, it's usually better to do..
function Hello() {};
Hello.prototype.greeting = "Hello";
Hello.prototype.greet = function () { return this.greeting };
Well the second approach (prototype) is more similar to standard classes in other languages like Python, in that you have a common "prototype" object which all instances are sharing. To compare the first and second approaches:
In approach 1, every time you call "new Foo()", you are creating a brand new object and inserting all the methods. This isn't very time or space efficient, since each Foo instance will have its own table of all the methods. You can test this by creating two Foo objects, and asking foo1.add == foo2.add (false). Approach 3 is very similar to this; I'm not sure what the semantic difference (if any) there is between approaches 1 and 3.
In approach 2, you have set up a shared prototype object containing all the methods. If you ask foo1.add == foo2.add, you get true. This is more space- and time-efficient. It also lets you add more methods to the prototype after creating instances, and they will see the new methods.
The problem with approach 2, as you say, is that you can't access the private members. But you can still add non-private members to the object itself, and access those using the prototype methods:
function Foo() {
this.private = 3;
}
Foo.prototype.add = function(bar) { return this.private + bar }
A caveat is that foo.private is visible externally.
The prototype one doesn't have a per object instance overhead only a per class overhead for the add function. This alone is the reason why I don't like the other two approaches.
Do not forget about inheritance. Some day you'll need. And for organizing inheritance the best approach is combined technic:
function Foo() {
this.array = [1, 2, 3];
this.add = function(bar) { return private + bar; }
}
Foo.prototype.add = function(bar) { }
var myFoo = new Foo();
Setting fields in constructor is useful to avoid modifying them by children objects.
Setting methods to prototype is faster then doing this every time in constructor.
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/