I prefer to use OOP in large scale projects like the one I'm working on right now. I need to create several classes in JavaScript but, if I'm not mistaken, there are at least a couple of ways to go about doing that. What would be the syntax and why would it be done in that way?
I would like to avoid using third-party libraries - at least at first.
Looking for other answers, I found the article Object-Oriented Programming with JavaScript, Part I: Inheritance - Doc JavaScript that discusses object-oriented programming in JavaScript. Is there a better way to do inheritance?
Here's the way to do it without using any external libraries:
// Define a class like this
function Person(name, gender){
// Add object properties like this
this.name = name;
this.gender = gender;
}
// Add methods like this. All Person objects will be able to invoke this
Person.prototype.speak = function(){
alert("Howdy, my name is" + this.name);
};
// Instantiate new objects with 'new'
var person = new Person("Bob", "M");
// Invoke methods like this
person.speak(); // alerts "Howdy, my name is Bob"
Now the real answer is a whole lot more complex than that. For instance, there is no such thing as classes in JavaScript. JavaScript uses a prototype-based inheritance scheme.
In addition, there are numerous popular JavaScript libraries that have their own style of approximating class-like functionality in JavaScript. You'll want to check out at least Prototype and jQuery.
Deciding which of these is the "best" is a great way to start a holy war on Stack Overflow. If you're embarking on a larger JavaScript-heavy project, it's definitely worth learning a popular library and doing it their way. I'm a Prototype guy, but Stack Overflow seems to lean towards jQuery.
As far as there being only "one way to do it", without any dependencies on external libraries, the way I wrote is pretty much it.
The best way to define a class in JavaScript is to not define a class.
Seriously.
There are several different flavors of object-orientation, some of them are:
class-based OO (first introduced by Smalltalk)
prototype-based OO (first introduced by Self)
multimethod-based OO (first introduced by CommonLoops, I think)
predicate-based OO (no idea)
And probably others I don't know about.
JavaScript implements prototype-based OO. In prototype-based OO, new objects are created by copying other objects (instead of being instantiated from a class template) and methods live directly in objects instead of in classes. Inheritance is done via delegation: if an object doesn't have a method or property, it is looked up on its prototype(s) (i.e. the object it was cloned from), then the prototype's prototypes and so on.
In other words: there are no classes.
JavaScript actually has a nice tweak of that model: constructors. Not only can you create objects by copying existing ones, you can also construct them "out of thin air", so to speak. If you call a function with the new keyword, that function becomes a constructor and the this keyword will not point to the current object but instead to a newly created "empty" one. So, you can configure an object any way you like. In that way, JavaScript constructors can take on one of the roles of classes in traditional class-based OO: serving as a template or blueprint for new objects.
Now, JavaScript is a very powerful language, so it is quite easy to implement a class-based OO system within JavaScript if you want to. However, you should only do this if you really have a need for it and not just because that's the way Java does it.
ES2015 Classes
In the ES2015 specification, you can use the class syntax which is just sugar over the prototype system.
class Person {
constructor(name) {
this.name = name;
}
toString() {
return `My name is ${ this.name }.`;
}
}
class Employee extends Person {
constructor(name, hours) {
super(name);
this.hours = hours;
}
toString() {
return `${ super.toString() } I work ${ this.hours } hours.`;
}
}
Benefits
The main benefit is that static analysis tools find it easier to target this syntax. It is also easier for others coming from class-based languages to use the language as a polyglot.
Caveats
Be wary of its current limitations. To achieve private properties, one must resort to using Symbols or WeakMaps. In future releases, classes will most likely be expanded to include these missing features.
Support
Browser support isn't very good at the moment (supported by nearly everyone except IE), but you can use these features now with a transpiler like Babel.
Resources
Classes in ECMAScript 6 (final semantics)
What? Wait. Really? Oh no! (a post about ES6 classes and privacy)
Compatibility Table – Classes
Babel – Classes
I prefer to use Daniel X. Moore's {SUPER: SYSTEM}. This is a discipline that provides benefits such as true instance variables, trait based inheritance, class hierarchies and configuration options. The example below illustrates the use of true instance variables, which I believe is the biggest advantage. If you don't need instance variables and are happy with only public or private variables then there are probably simpler systems.
function Person(I) {
I = I || {};
Object.reverseMerge(I, {
name: "McLovin",
age: 25,
homeState: "Hawaii"
});
return {
introduce: function() {
return "Hi I'm " + I.name + " and I'm " + I.age;
}
};
}
var fogel = Person({
age: "old enough"
});
fogel.introduce(); // "Hi I'm McLovin and I'm old enough"
Wow, that's not really very useful on it's own, but take a look at adding a subclass:
function Ninja(I) {
I = I || {};
Object.reverseMerge(I, {
belt: "black"
});
// Ninja is a subclass of person
return Object.extend(Person(I), {
greetChallenger: function() {
return "In all my " + I.age + " years as a ninja, I've never met a challenger as worthy as you...";
}
});
}
var resig = Ninja({name: "John Resig"});
resig.introduce(); // "Hi I'm John Resig and I'm 25"
Another advantage is the ability to have modules and trait based inheritance.
// The Bindable module
function Bindable() {
var eventCallbacks = {};
return {
bind: function(event, callback) {
eventCallbacks[event] = eventCallbacks[event] || [];
eventCallbacks[event].push(callback);
},
trigger: function(event) {
var callbacks = eventCallbacks[event];
if(callbacks && callbacks.length) {
var self = this;
callbacks.forEach(function(callback) {
callback(self);
});
}
},
};
}
An example of having the person class include the bindable module.
function Person(I) {
I = I || {};
Object.reverseMerge(I, {
name: "McLovin",
age: 25,
homeState: "Hawaii"
});
var self = {
introduce: function() {
return "Hi I'm " + I.name + " and I'm " + I.age;
}
};
// Including the Bindable module
Object.extend(self, Bindable());
return self;
}
var person = Person();
person.bind("eat", function() {
alert(person.introduce() + " and I'm eating!");
});
person.trigger("eat"); // Blasts the alert!
Disclosure: I am Daniel X. Moore and this is my {SUPER: SYSTEM}. It is the best way to define a class in JavaScript.
var Animal = function(options) {
var name = options.name;
var animal = {};
animal.getName = function() {
return name;
};
var somePrivateMethod = function() {
};
return animal;
};
// usage
var cat = Animal({name: 'tiger'});
Following are the ways to create objects in javascript, which I've used so far
Example 1:
obj = new Object();
obj.name = 'test';
obj.sayHello = function() {
console.log('Hello '+ this.name);
}
Example 2:
obj = {};
obj.name = 'test';
obj.sayHello = function() {
console.log('Hello '+ this.name);
}
obj.sayHello();
Example 3:
var obj = function(nameParam) {
this.name = nameParam;
}
obj.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
Example 4: Actual benefits of Object.create(). please refer [this link]
var Obj = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var usrObj = Object.create(Obj); // <== one level of inheritance
usrObj.init('Bob');
usrObj.sayHello();
Example 5 (customised Crockford's Object.create):
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
To keep answer updated with ES6/ ES2015
A class is defined like this:
class Person {
constructor(strName, numAge) {
this.name = strName;
this.age = numAge;
}
toString() {
return '((Class::Person) named ' + this.name + ' & of age ' + this.age + ')';
}
}
let objPerson = new Person("Bob",33);
console.log(objPerson.toString());
I think you should read Douglas Crockford's Prototypal Inheritance in JavaScript and Classical Inheritance in JavaScript.
Examples from his page:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Effect? It will allow you to add methods in more elegant way:
function Parenizor(value) {
this.setValue(value);
}
Parenizor.method('setValue', function (value) {
this.value = value;
return this;
});
I also recommend his videos:
Advanced JavaScript.
You can find more videos on his page: http://javascript.crockford.com/
In John Reisig book you can find many examples from Douglas Crockfor's website.
Because I will not admit the YUI/Crockford factory plan and because I like to keep things self contained and extensible this is my variation:
function Person(params)
{
this.name = params.name || defaultnamevalue;
this.role = params.role || defaultrolevalue;
if(typeof(this.speak)=='undefined') //guarantees one time prototyping
{
Person.prototype.speak = function() {/* do whatever */};
}
}
var Robert = new Person({name:'Bob'});
where ideally the typeof test is on something like the first method prototyped
If you're going for simple, you can avoid the "new" keyword entirely and just use factory methods. I prefer this, sometimes, because I like using JSON to create objects.
function getSomeObj(var1, var2){
var obj = {
instancevar1: var1,
instancevar2: var2,
someMethod: function(param)
{
//stuff;
}
};
return obj;
}
var myobj = getSomeObj("var1", "var2");
myobj.someMethod("bla");
I'm not sure what the performance hit is for large objects, though.
var Student = (function () {
function Student(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
this.fullname = firstname + " " + lastname;
}
Student.prototype.sayMyName = function () {
return this.fullname;
};
return Student;
}());
var user = new Student("Jane", "User");
var user_fullname = user.sayMyName();
Thats the way TypeScript compiles class with constructor to JavaScript.
The simple way is:
function Foo(a) {
var that=this;
function privateMethod() { .. }
// public methods
that.add = function(b) {
return a + b;
};
that.avg = function(b) {
return that.add(b) / 2; // calling another public method
};
}
var x = new Foo(10);
alert(x.add(2)); // 12
alert(x.avg(20)); // 15
The reason for that is that this can be bound to something else if you give a method as an event handler, so you save the value during instantiation and use it later.
Edit: it's definitely not the best way, just a simple way. I'm waiting for good answers too!
You probably want to create a type by using the Folding Pattern:
// Here is the constructor section.
var myType = function () {
var N = {}, // Enclosed (private) members are here.
X = this; // Exposed (public) members are here.
(function ENCLOSED_FIELDS() {
N.toggle = false;
N.text = '';
}());
(function EXPOSED_FIELDS() {
X.count = 0;
X.numbers = [1, 2, 3];
}());
// The properties below have access to the enclosed fields.
// Careful with functions exposed within the closure of the
// constructor, each new instance will have it's own copy.
(function EXPOSED_PROPERTIES_WITHIN_CONSTRUCTOR() {
Object.defineProperty(X, 'toggle', {
get: function () {
var before = N.toggle;
N.toggle = !N.toggle;
return before;
}
});
Object.defineProperty(X, 'text', {
get: function () {
return N.text;
},
set: function (value) {
N.text = value;
}
});
}());
};
// Here is the prototype section.
(function PROTOTYPE() {
var P = myType.prototype;
(function EXPOSED_PROPERTIES_WITHIN_PROTOTYPE() {
Object.defineProperty(P, 'numberLength', {
get: function () {
return this.numbers.length;
}
});
}());
(function EXPOSED_METHODS() {
P.incrementNumbersByCount = function () {
var i;
for (i = 0; i < this.numbers.length; i++) {
this.numbers[i] += this.count;
}
};
P.tweak = function () {
if (this.toggle) {
this.count++;
}
this.text = 'tweaked';
};
}());
}());
That code will give you a type called myType. It will have internal private fields called toggle and text. It will also have these exposed members: the fields count and numbers; the properties toggle, text and numberLength; the methods incrementNumbersByCount and tweak.
The Folding Pattern is fully detailed here:
Javascript Folding Pattern
Code golf for #liammclennan's answer.
var Animal = function (args) {
return {
name: args.name,
getName: function () {
return this.name; // member access
},
callGetName: function () {
return this.getName(); // method call
}
};
};
var cat = Animal({ name: 'tiger' });
console.log(cat.callGetName());
MooTools (My Object Oriented Tools) is centered on the idea of classes. You can even extend and implement with inheritance.
When mastered, it makes for ridiculously reusable, powerful javascript.
Object Based Classes with Inheritence
var baseObject =
{
// Replication / Constructor function
new : function(){
return Object.create(this);
},
aProperty : null,
aMethod : function(param){
alert("Heres your " + param + "!");
},
}
newObject = baseObject.new();
newObject.aProperty = "Hello";
anotherObject = Object.create(baseObject);
anotherObject.aProperty = "There";
console.log(newObject.aProperty) // "Hello"
console.log(anotherObject.aProperty) // "There"
console.log(baseObject.aProperty) // null
Simple, sweet, and gets 'er done.
Based on the example of Triptych, this might even be simpler:
// Define a class and instantiate it
var ThePerson = new function Person(name, gender) {
// Add class data members
this.name = name;
this.gender = gender;
// Add class methods
this.hello = function () { alert('Hello, this is ' + this.name); }
}("Bob", "M"); // this instantiates the 'new' object
// Use the object
ThePerson.hello(); // alerts "Hello, this is Bob"
This only creates a single object instance, but is still useful if you want to encapsulate a bunch of names for variable and methods in a class. Normally there would not be the "Bob, M" arguments to the constructor, for example if the methods would be calls to a system with its own data, such as a database or network.
I am still too new with JS to see why this does not use the prototype thing.
A base
function Base(kind) {
this.kind = kind;
}
A class
// Shared var
var _greeting;
(function _init() {
Class.prototype = new Base();
Class.prototype.constructor = Class;
Class.prototype.log = function() { _log.apply(this, arguments); }
_greeting = "Good afternoon!";
})();
function Class(name, kind) {
Base.call(this, kind);
this.name = name;
}
// Shared function
function _log() {
console.log(_greeting + " Me name is " + this.name + " and I'm a " + this.kind);
}
Action
var c = new Class("Joe", "Object");
c.log(); // "Good afternoon! Me name is Joe and I'm a Object"
JavaScript is object-oriented, but it's radically different than other OOP languages like Java, C# or C++. Don't try to understand it like that. Throw that old knowledge out and start anew. JavaScript needs a different thinking.
I'd suggest to get a good manual or something on the subject. I myself found ExtJS Tutorials the best for me, although I haven't used the framework before or after reading it. But it does give a good explanation about what is what in JavaScript world. Sorry, it seems that that content has been removed. Here's a link to archive.org copy instead. Works today. :P
//new way using this and new
function Persons(name) {
this.name = name;
this.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
};
}
var gee=new Persons("gee");
gee.greeting();
var gray=new Persons("gray");
gray.greeting();
//old way
function createPerson(name){
var obj={};
obj.name=name;
obj.greeting = function(){
console.log("hello I am"+obj.name);
};
return obj;
}
var gita=createPerson('Gita');
gita.greeting();
I would like to implement a builder using closures in JavaScript. I feel it can be done, but am struggling to put it into code.
I have something like this but I feel there is probably a better solution leveraging something like partial application.
function Builder() {
this.spec = {};
}
Builder.prototype.withFoo = function(value) {
this.spec.foo = value;
return this;
};
Builder.prototype.withBar = function(value) {
this.spec.bar = value;
return this;
};
Builder.prototype.build = function() {
var result = {};
result.foo = this.spec.foo;
result.bar = this.spec.bar;
this.spec = {}; // This is to avoid accidentally using the same builder repeatedly.
return result;
};
var builder = new Builder();
builder.withFoo('foo value')
.withBar('foo value')
.build(); // { foo: 'foo value' , bar: 'bar value' }
Can anyone help me do this?
Edit: The key thing here is that I want the object to be instantiated lazily.
Here is an alternative approach:
function Builder(obj){
return obj;
}
This is called by Fowler and Martin the "Identity Builder" and is quite common in enterprise architecture. It has the advantage of supporting arbitrarily nested hierarchies of objects and sub objects and it is completely generic.
var myBuildObject = Builder({
spec: {
foo: foo,
bar: bar
}
});
It does so much more though, it can also easily specify arrays:
var myBuildObject = Builder({
spec: [....]
});
It can be extended and subclassed with more sophisticated builders that can in turn do return Builder.call(this, obj) after decorating it.
It can even specify getters/setters.
It is usual with a builder to be able to chain the calls together, so something like the below should do what you're after:
var builder = (function(){
var obj = {};
return {
withFoo: function(foo){
obj.foo = foo;
return this;
},
withBar: function(bar){
obj.bar = bar;
return this;
},
build: function(){
var rtn = obj;
obj = {}; // clear so you can use builder again
return rtn;
}
}
})();
var result = builder.withFoo("foo")
.withBar("bar")
.build();
console.log(result); // { foo: 'foo' , bar: 'bar' }
Having said that, I like to have an instance of the builder, so in all honesty I prefer your original (except with return this to return the current instance of the builder from the methods). So I'd personally go with:
function Builder() {
this.spec = {};
}
Builder.prototype.withFoo = function(value) {
this.spec.foo = value;
return this;
};
Builder.prototype.withBar = function(value) {
this.spec.bar = value;
return this;
};
Builder.prototype.build = function() {
return this.spec;
};
var result = new Builder()
.withFoo('foo value')
.withBar('foo value')
.build();
Note there is no need to clear out spec when callingbuild - a new instance of Builder will have a new instance of spec!
One simple way to invoke code lazily is partial application and currying in particular.
Let's say you have a Person type and it looks like this:
function Person(name, lastName, age, height){
return {
name: name,
lastName: lastName,
age: age,
height: height
};
}
var pete = Person("Pete", "Doe", 40, 6.4);
What we really want it to do - is to be able to specify only some of those properties initially and some later:
var namedJoeDoe = Person("Joe", "Doe"); // won't work today
var tallJoe = namedJoeDoe(40, 8.6); // one object
var shortJoe = namedJoeDoe(40, 4.3); // another object
We only create the object (and your real objects are probably larger at the very end. This is currying, and if we use Ramda's curry we can write it as such:
Person = R.curry(Person); // impl at src/curryN.js
We get exactly this functionality, quoting the docs:
Returns a curried equivalent of the provided function. The curried function has two unusual capabilities. First, its arguments needn't be provided one at a time. If f is a ternary function and g is R.curry(f), the following are equivalent:
g(1)(2)(3)
g(1)(2, 3)
g(1, 2)(3)
g(1, 2, 3)
That is, only when you've supplied all properties for a person will an instance be created.
Some methods of one of my classes right now are public, but can access private variables (they are privileged). This is because they are created in the class constructor, so their closure has access to the object closure.
What I would like to avoid, though, is the memory and performance overhead of creating new privileged methods every time. So I want to share them.
Is there any way to put privileged methods into a prototype?
Example was requested:
function Person(age) { // age is private
this.grow = function() { // grow is now public, but can access private "age"
age += 1;
}
}
dan = new Person(10);
dan.grow();
dan.age; // undefined
This works, I have a public method "grow" that can access the private variable "age", but grow has to be recreated for each object.
The more performant way is:
function Person(age) { // age is private
this.age = age; // but this.age is public
}
Person.prototype.grow = function() {
this.age += 1;
}
dan = new Person(10);
dan.grow();
dan.age; // 11
This shares the "grow" method, but now age is public.
You could do something like this (without ES6), though I don't consider it a good solution.
var Person = (function () {
var id = 0,
data = {},
key = Math.random();
function Person(age) {
var thisId = id;
data[id] = age;
id += 1;
this.getId = function(check) {
if (check !== key) {
return undefined;
}
return thisId;
};
}
Person.prototype.grow = function () {
var thisId = this.getId(key);
data[thisId] += 1;
console.log(data[thisId]);
return this;
};
Person.prototype.destroy = function () {
var thisId = this.getId(key);
data[thisId] = null;
delete data[thisId];
};
return Person;
}());
var dan = new Person(10);
dan.grow();
console.log(dan.age); // undefined
console.log(dan.getId()); // undefined
on jsFiddle
Added by #DanRedux:
function Person(age) {
this.private = {age:age}; }
Person.prototype.grow = function() {
this.private.age += 1; }
dan = new Person(10);
dan.grow();
dan.age; // undefined
dan.private.age; // 11
Yes, it is indeed possible. However it requires a little bit of trickery:
var createTree = require("functional-red-black-tree");
var Person = (function () {
var tree = createTree(), id = 0;
return function (age) {
tree.insert(id, {
age: age
});
this.id = id++;
this.grow = grow;
this.destroy = destroy;
};
function grow() {
tree.get(this.id).age++;
}
function destroy() {
tree.remove(this.id);
}
}());
We use functional red black trees to efficiently insert, remove and get the private properties of an object in O(log n) time. Hence for example say you create 2251799813685248 instances of Person at a time. It will still only require 51 operations to insert, remove and get objects from the tree.
You can use it as follows:
var dan = new Person(10);
dan.grow();
dan.age; // undefined
dan.destroy(); // frees shared memory
However I wouldn't recommend this approach because:
It unnecessarily complicates things.
If you forget to call destroy then you will waste a lot of memory.
Every "privileged" function has an additional overhead.
Changes made to the secret object are not reflected on the private variables.
Instead I would recommend that you just use public properties for everything. There's really no good reason to use private properties at all. What are you scared of?
Edit: If alll you want is to prevent your private properties from being printed out via console.log then you can make them non-enumerable:
function Person(age) {
Object.defineProperty(this, "age", {
enumerable: false,
writable: true,
value: age
});
}
Person.prototype.grow = function () {
this.age++;
};
Now the age property (although public) will not appear in for in loops or via console.log. In short you get the best of both worlds.
As I said in the comments, there's absolutely no need to use the shared privileged method hack. Simply make all your variables public and non-enumerable.
In addition prefix them with an underscore to indicate that they should not be tampered with. All good JavaScript programmers use this convention.
Well, as you have said, privileged methods are created by placing them in the constructor scope. By that definition, they cannot be shared amongst instances; otherwise they wouldn't be able to access the instance-specific scope.
Let's take this object:
var person = {
_name: "John",
name: function() {return _name}
}
In GUI,
myTextBox.value = person.name()
will return
"John"
But
myTextBox.value = person.name
will return
function() {return _name}
How can I force both syntax to return "John"? Could I use a closure (question I asked previously) somehow here?
You can't!
You can't override javascript operators or keywords.
you really can't have one operator\keyword that does two different things in the same context!
Ok, had a play and it looks like this is "possible" (At least in chrome) but its a bit of a dirty hack.
var person = {
_name: "John",
name: function() {return this._name;},
}
person.name.toString = function(){ return person._name; }
Which will result in both person.name and person.name() returning "John".
If you support only modern browsers you can use a ES5 Getters, but in general this is JavaScript, why are you trying to make it complicated?
Your alternatives are:
make a rule that you have to use the function to access the variable (yuck)
don't worry about it.
I'd go for #2.
I think you're getting confused with this syntax here, but actually it has the same problem as you do now:
function Person(name) {
this._name = name;
}
Person.prototype.name = function(name) {
if (name) this._name = name;
return this._name;
}
var j = new Person("Jay");
j.name() // "Jay"
j.name("Thomas"); // I can set the value as well
j.name() // "Thomas"
It seems like you're trying to create real private variables, which are possible, but probably not that helpful.
function Person(name) {
var myName = name; // private
this.name = function() {
return myName;
}
}
var j = new Person("Jay");
j.name(); // still had to use perens
Finally because yours is just a simple object, we can do this. Not sure why you'd want to though:
var person = {};
(function(name) {
var myName = name; // myName and name, both private, but not helpful
person = {
name = myName
}
}("Jay"))
person.name // "Jay"
I have this piece of code:
var Human=function(name){
this._name=name;
};
Human.prototype.Shout=function(){
alert(this._name);
};
var tom=new Human("tom");
var john=new Human("john");
alert(tom.Shout===john.Shout);
Right now ._name is not "private". I want to make ._name "private", but at the same time i do not wish to create additional functions for each instance of Human (in other words tom.Shout Must be === to john.Shout) because creating additional functions for each instance is just well.. unnecessary (ok offtopic - we can debate this on another thread)
My conclusion is that what I'm trying to achieve (having ._name be "private" and at the same time having tom.Shout===john.Shout) is impossible.
But I just want to be 200% sure before jumping into any conclusions.
(I welcome any hacks as long as the requirements are met, i.e no creating of additional functions for each instance)
If we have to create additional functions to do scoping that's fine but that number should be a fixed number and that number should not increase with each additional instance of Human.
Update
Your looking for #name which is an instance variable. Pray it's in es.next, but we don't have it yet. Maybe in two years.
If you care about a clean API then here is your solution:
function Class(foo) {
Class.priv(this).foo = foo;
}
Class.priv = (function() {
var cache = [],
uid = 1;
return function(obj) {
if (!this.__id) {
this.__id = uid;
cache[uid++] = {};
}
return cache[this.__id];
};
}());
Class.prototype.bar = function() {
console.log(Class.priv(this).foo);
}
Store all the data in a cache as a function of the constructor. No data is cluttered on the object.
Original
However there is no such thing as "private".
All you can do is create a local variable inside a function.
The constructor function
var Human = function(name) {
// local variable.
var _name = name;
}
Has a local variable that by very definition of being local is not usable outside of the constructor function.
This means that you cannot access it in external code like the prototype.
What you can do however is make it read only using ES5
var Human = function(name) {
Object.defineProperty(this, "name", { value: name });
}
If you can truly achieve what your asking, you'd make a huge breakthrough in js. I've attempted to do just that for many hours.
A different pattern would be :
var Human = function(name) {
this.name = name;
return {
Shout: this.Shout.bind(this)
};
}
Human.prototype.Shout = function() {
console.log(this.name);
}
This has the overhead of calling .bind and creating a new object for every instance though.
how about this ?
var Human = function (name) {
var _name = name;
this.getName = function () {
return _name;
}
};
Human.prototype.Shout = function () {
alert(this.getName());
};
var tom = new Human("tom");
var john = new Human("john");
tom.Shout(); // tom
john.Shout(); // john
alert(tom.Shout === john.Shout); // true
EDIT:
the former creates another function for GET property,
it is not possible without creating additional functions.
Did read the question, didn't understand, because this._name is just not private, so the question is a bit weird. This is how in my test the prototype methods are added once and available to all instances. I repeat: this._name is not private here. If you add a local variable, and want to access it via a closure in a prototype method, calling the value of the local variable will result in the same value for all instances.
Anyway, with this constructor function the this._name getter and shout methods are added to the prototype chain once and thereby available for all instances of Human.
function Human(name) {
if (!(this instanceof Human)){
return new Human(name);
}
this._name = name;
if (!Human.prototype.Name){
Human.prototype.Name = function(val){
if (val){
this._name = val;
return this;
}
return this._name;
};
Human.prototype.shout = function(){
alert(this._name);
}
}
}