how do i namespace pseudo-classical javascript - javascript

I have some simple OO code I've written that I'm playing with:
//define a constructor function
function person(name, sex) {
this.name = name;
this.sex = sex;
}
//now define some instance methods
person.prototype.returnName = function() {
alert(this.name);
}
person.prototype.returnSex = function() {
return this.sex;
}
person.prototype.talk = function(sentence) {
return this.name + ' says ' + sentence;
}
//another constructor
function worker(name, sex, job, skills) {
this.name = name;
this.sex = sex;
this.job = job;
this.skills = skills;
}
//now for some inheritance - inherit only the reusable methods in the person prototype
//Use a temporary constructor to stop any child overwriting the parent prototype
var f = function() {};
f.prototype = person.prototype;
worker.prototype = new f();
worker.prototype.constructor = worker;
var person = new person('james', 'male');
person.returnName();
var hrTeamMember = new worker('kate', 'female', 'human resources', 'talking');
hrTeamMember.returnName();
alert(hrTeamMember.talk('I like to take a lot'));
Now this is all well and good. But I'm confused. I want to include namespacing as part of my code writing practice. How can I namespace the above code. As it is now I have 2 functions defined in the global namespace.
The only way I can think to do this is to switch to object literal syntax. But then how do I implement the pseudo-classical style above with object literals.

You could for example do following:
var YourObject;
if (!YourObject) {
YourObject = {};
YourObject.Person = function(name, sex) {
// ...
}
YourObject.Person.prototype.returnName = function() {
// ...
}
// ...
}

You don't have to use object literals, at least, not exclusively.
Decide on the single global symbol you'd like to use.
Do all your declaration work in an anonymous function, and explicitly attach "public" methods as desired to your global object:
(function(global) {
// all that stuff
global.elduderino = {};
global.elduderino.person = person;
global.elduderino.worker = worker;
})(this);
I may not be completely understanding the nuances of your issue here, but the point I'm trying to make is that Javascript makes it possible for you to start with your symbols being "hidden" as locals in a function, but they can be selectively "exported" in various ways.

Related

In javascript, Is there a perfect way to define class

I am looking for a perfect way to define class. "perfect" here means:`
create instances will not create copies of methods.
public function could easily(not to much hassle) access private variable
For example, way 1:
function Foo1() {
var private1;
this.publicMethod1 = function() {//create instance will create copy of this function}
}
will not meet rule No.1 above.
Another example, way 2:
function Foo2() {
var private2;
}
Foo2.prototype.Method2 = function() {//cannot access private2}
will not meet rule No.2 above.
So is it possible to meet both rules? Thanks.
In JavaScript it's more about conventions. Private properties or methods are defined with a underscore first like _private. With a few helpers you can make classes easily. I find this setup easy enough, all you need is a helper inherits to extend classes, and instead of using multiple arguments you pass in an object props and simply call "super" on the inherited classes with arguments. For example, using a module pattern:
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype);
};
var Person = (function PersonClass() {
function Person(props) {
this.name = props.name || 'unnamed';
this.age = props.age || 0;
}
Person.prototype = {
say: function() {
return 'My name is '+ this.name +'. I am '+ this.age +' years old.';
}
};
return Person;
}());
var Student = (function StudentClass(_super) {
Student.inherits(_super);
function Student(props) {
_super.apply(this, arguments);
this.grade = props.grade || 'untested';
}
Student.prototype.say = function() {
return 'My grade is '+ this.grade +'.';
};
return Student;
}(Person));
var john = new Student({
name: 'John',
age: 25,
grade: 'A+'
});
console.log(JSON.stringify(john)); //=> {"name":"John","age":25,"grade":"A+"}
console.log(john.say()); //=> "My grade is A+"
About the private variable "issue" just stick to convention for instance properties and use closures when needed for everything else private.
function Foo3() {
this.private = {};
}
Foo3.prototype.set_x = function (x) {
this.private.x = x;
};
To make a long story short: no, it is not. You cannot extend the prototype with methods that could access private variables. At least if these private variables are made private via a closure.
Though, it is a convention in javascript that you mark your private fields with an underscore, for example _myPrivateField. These would be still public, but i have seen this solution being used in many libraries and i also prefer that style to meet your first rule.
A basic example is below:
Foo = function(id)
{
// private instances.
var _id;
var _self = this;
// constructor
_id = id;
// private method
function _get()
{
return _id;
};
// public function
_self.set = function(id)
{
_id = id;
};
_self.get = function()
{
return _get();
};
};
var bar = Foo(100);
console.log( bar.get() );
bar.set(1000);
console.log( bar.get() );
I would recommend you use prototype.

JavaScript class prototyping using module pattern

I was searching of way to define a class in JavaScript. I came up with hybrid Module and Prototype pattern, but not sure if I don't miss something. Basically I wanted to use 'this' keyword. Example:
var A = function()
{
this.x = 10;
};
A.prototype = (function()
{
function privatePrint()
{
alert("Printing from private! x:" + this.x);
}
this.print = function()
{
privatePrint.call(this);
};
return this;
}).apply(A.prototype);
var a = new A();
a.print();
Return value is just for readability - A.prototype can be used in the beginning.
Patterns I also tried:
Module : 'new' keyword cannot be used.
Prototype, Revealing Prototype :
no extending if private functions declared in prototype declaration
(public methods returned by object)
Is my approach acceptable?
**Public**
function Constructor(...) {
this.membername = value;
}
Constructor.prototype.membername = value;
**Private**
function Constructor(...) {
var that = this;
var membername = value;
function membername(...) {...}
}
Note: The function statement
function membername(...) {...}
is shorthand for
var membername = function membername(...) {...};
**Privileged**
function Constructor(...) {
this.membername = function (...) {...};
}
It's over two years since you asked, but in Googling for a similar approach I ended up here. I don't see a drawback to your implementation other than (since you are essentially asking for an opinion) it seeming a tad confusing why you are passing the prototype in as an import on the IIFE.
Otherwise, what you've got looks very similar to other "standard" implementations of the "Revealing Prototype Pattern" which I've seen essentially as such:
(function (NS) {
'use strict';
// constructor for the Person "Class", attached to your global namespace
var Person = NS.Person = function (name) {
// set properties unique for each instance
this.name = name;
};
// may not be necessary, but safe
Person.prototype.constructor = Person;
// private method
var _privateMethod = function() {
// do private stuff
// use the "_" convention to mark as private
// this is scoped to the modules' IIFE wrapper, but not bound the returned "Person" object, i.e. it is private
};
// public method
Person.prototype.speak = function() {
console.log("Hello there, I'm " + this.name);
};
return Person;
})(window.NS = window.NS || {}); // import a global namespace
// use your namespaced Person "Class"
var david = new NS.Person("David");
david.speak();
There is also a similar module pattern, the structure of which might be more like the "Class" implementation you are after:
(function (NS) {
'use strict';
// constructor for the Person "Class", attached to your global namespace
var Person = NS.Person = function (name) {
// reset constructor (the prototype is completely overwritten below)
this.constructor = Person;
// set properties unique for each instance
this.name = name;
};
// all methods on the prototype
Person.prototype = (function() {
// private method
var _privateMethod = function() {
// do private stuff
// use the "_" convention to mark as private
// this is scoped to the IIFE but not bound to the returned object, i.e. it is private
};
// public method
var speak = function() {
console.log("Hello there, I'm " + this.name);
};
// returned object with public methods
return {
speak: speak
};
}());
})(window.NS = window.NS || {}); // import a global namespace
// use your namespaced Person "Class"
var david = new NS.Person("David");
david.speak();
Gist: https://gist.github.com/dgowrie/24fb3483051579b89512

class variable in Javascript

How do I declare class variables in Javascript.
function Person(){
fname = "thisfname"; //What needs to be put here
}
alert(Person.fname) //It should alert "thisFrame"
I don't want to use this approach.
function Person(){
}
Person.fname = "thisfname";
alert(Person.fname) //alerts "thisframe"
JavaScript does not have classes like others have said. Inheritance is resolved through prototyping which in essence does nothing more than create non-deletable property references on a newly created object. JavaScript also has alternatives for simple data objects, namely object literals.
The variation of a 'Class' in JavaScript should be defined as such:
// I use function statements over variable declaration
// when a constructor is involved.
function Person(name) {
this.name = name;
}
// All instances of Person create reference methods to it's prototype.
// These references are not deletable (but they can be overwritten).
Person.prototype = {
speak: function(){
alert(this.name + ' says: "Hello world!"');
}
};
var Mary = new Person('Mary');
Mary.speak(); // alerts 'Mary says: "Hello world!"'
The this reference always points to the owner of the function. If you call Person without the new operator, the owner will be the global scope (window). If you do not use this reference to assign properties to your instance, then the properties will simply be declared as variables. If you do not use the var statement, then those declarations will create global variables which are bad!
more about this
Using the this reference in a constructor function is exceedingly important if you want to add properties to the current instance. Without using this, you only create a variable (which is not the same as a property) and as mentioned, if you don't use the var statement either, you create global variables.
function Person(){
name = 'Mary'
}
var p = new Person();
alert(p.name); // undefined, did not use 'this' to assign it to the instance.
alert(name); // 'Mary', boo, it created a global variable!
Use this!
function Person(){
this.name = 'Mary'
}
var p = new Person();
alert(p.name); // 'Mary', yay!
alert(name); // undefined, yay!
Note, anything assigned to an instance through the function constructor CANNOT BE INHERITED unless you assign it to the prototype and overwrite it again in the function constructor to make it an owned property.
When you create a new instance of through a function doubling as a constructor, actually the following happens.
pseudo code:
copy Person.prototype as person
invoke Person function on person
return person
Actually, this is what happens in every classical language when you create an instance of a class. But the main difference in JavaScript is that it's not encapsulated inside a nice Class statement. Originally JavaScript didn't even have function constructors but was added on later because SUN demanded they wanted JavaScript to be more like Java.
Object literals
The alternative for function constructors for objects that carry only intrinsic data and no methods are object literals.
var Mary = {
firstName: 'Mary',
lastName: 'Littlelamb'
};
Which is the prefered way of declaring intrinsic objects rather then:
// do not ever do this!
var Mary = new Object();
Mary.firstName = 'Mary';
Mary.lastName = 'Littlelamb';
With object literals in your skill set, you can create a factory pattern for intrinsic data objects using the module pattern (which is usually for singletons).
var createPerson = function(firstName, lastName){
return {
firstName: firstName,
lastName: lastName
}
}
var Mary = createPerson('Mary', 'Littlelamb');
This achieves some comfortable encapsulation, but can only be used for intrinsic data objects.
Another thing you can do with Object literals and JavaScript is delegation, which should be preferred.
var personMethods = {
speak: function(){
alert(this.firstName + ' says: "Hello world!"');
}
};
var Mary = {
firstName: "Mary",
lastName: "Littlelamb"
};
var Peter = {
firstName: "Peter",
lastName: "Crieswolf"
};
personMethods.speak.apply(Mary); // alerts 'Mary says: "Hello world!"'
personMethods.speak.apply(Peter); // alerts 'Peter says: "Hello world!"'
Why should this be preferred? Because it keeps your objects minute and readable, even prototypical references take up memory and when using inheritance and 'subclassing' you end up with child instances that have lots of unused method references. Delegation is always better.
The way you mentioned is how to define class variables, the other way (inside function Person) is to define instance properties.
function Person(name){
this.name = name;
}
Person.specie = "Human";
alert(Person.specie) //alerts "Human", a class variable.
var john = new Person('John');
alert(john.name); //alerts "John", an object property.
It is important to understand that there is no such thing as classes in JavaScript. There are some frameworks out there that simulate a classical inheritance pattern, but technically it all boils down to constructor functions and prototypes.
So, you may want to do something like
PersonProto = { // the "class", or prototype
fname: "thisfname"
};
function Person() { // the constructor function
this.instanceVar = 'foo';
}
Now, connect the constructor to the prototype:
Person.prototype = PersonProto;
And, voilà:
var a = new Person();
alert(a.fname);
function Person(){
this.fname = null;
this.lname = null;
this.set_fname = set_fname;
this.set_lname = set_lname;
this.get_name = get_name;
}
/* Another way
function Person(fname, lname){
this.fname = fname;
this.lname = lname;
this.get_name = get_name;
}*/
function set_fname(fname){
this.fname = fname;
}
function set_lname(y){
this.lname = lname;
}
function get_name(){
with (this) {
return fname + ' ' + lname;
}
}
person_obj = new Person();
person_obj.set_fname('Foo');
person_obj.set_lname('Bar');
// person_obj = new Person('Foo', 'Bar');
person_obj = get_name(); // returns "Foo Bar"
Can't think of better example.
3 ways to define a variables to JavaScript class:
1)To define properties created using function(), you use the 'this' keyword
function Apple (type) {
this.type = type;
this.color = "red";
}
To instantiate an object of the Apple class, set some properties you can do the following:
var apple = new Apple('macintosh');
apple.color = "reddish";
2) Using Literal Notation
var apple = {
type: "macintosh",
color: "red"
}
In this case you don't need to (and cannot) create an instance of the class, it already exists.
apple.color = "reddish";
3) Singleton using a function
var apple = new function() {
this.type = "macintosh";
this.color = "red";
}
So you see that this is very similar to 1 discussed above, but the way to use the object is exactly like in 2.
apple.color = "reddish";
You can also try this approach:
function name() {
this.name;
this.lastname;
}
name.prototype.firstName = function(name) {
this.name = name;
alert(this.name);
}
var x = new name();
x.firstName("Kartikeya");

Popular JavaScript Inheritance Patterns

I'm working on an ebook on GitHub on TDD JavaScript and I'm wondering if I'm missing any popular inheritance patterns. If you know of any additional patterns I'd love to see them. They should have the following:
Time tested - used in real apps
Source code should be supplied. Should be as straight forward and pedantic as possible.
Of course be correct and working.
The reason I'm doing this is that it seems that object inheritance in JavaScript has been quite difficult for many of us to grok. my JavaScript inheritance chapter is basically a study aid to: Crockford's Good Parts and Zakas's Professional JavaScript for Web Developers.
Here are the patterns I have so far:
// Pseudoclassical Inheritance
function Animal(name) {
this.name = name;
this.arr = [1,2,3];
};
Animal.prototype = {
constructor: Animal,
whoAmI: function() { return "I am " + this.name + "!\n"; }
};
function Dog(name, breed) {
this.name = name;
this.breed = breed;
};
Dog.prototype = new Animal();
Dog.prototype.getBreed = function() {
return this.breed;
};
Dog.prototype.bark = function() {
return 'ruff ruff';
};
// Combination Inheritance
function Parent(name) {
this.name = name;
this.arr = [1,2,3];
};
Parent.prototype = {
constructor: Parent,
toString: function() { return "My name is " + this.name; }
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
};
Child.prototype = new Parent();
Child.prototype.getAge = function() {
return this.age;
};
// Prototypal Inheritance
var helper = { // Thanks to Bob Vince for reminding me NOT to clobber Object!
inherit: function(p) {
NewObj = function(){};
NewObj.prototype = p;
return new NewObj();
},
inheritPrototype: function(subType, superType) {
var prototype = helper.inherit(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
};
function SubType(name, age) {
Parent.call(this, name);
this.age = age;
};
//Child.prototype = new Parent(); // Gets replaced by:
helper.inheritPrototype(SubType, Parent);
SubType.prototype.getAge = function() {
return this.age;
};
// Functional - Durable Pattern
function super_func(blueprint) {
var obj = {};
obj.getName = function() { return blueprint.name; };
obj.getAge = function() { return blueprint.age; };
obj.getFoo = function() { return blueprint.foo; };
obj.getBar = function() { return blueprint.bar; };
return obj;
};
function sub_func(blueprint) {
blueprint.name = blueprint.name || "Crockford's Place";
supr = super_func(blueprint);
supr.coolAugment = function() { return "I give a fresh new perspective on things!" };
return supr;
};
And for those interested, here are the jspec tests (sorry but Markdown or whatever they're using mangles the format a bit):
describe 'JavaScript Inheritance Tests'
before_each
animal = new Animal("Onyx")
dog = new Dog("Sebastian", "Lab")
person = { password : 'secret', toString : function(){ return '<Person>' } }
stub(person, 'toString').and_return('Original toString method!')
end
describe 'Pseudoclassical Inheritance Creation'
it 'should create parent and child object using pseudoclassical inheritance'
animal.constructor.should.eql Animal
// dog.constructor.should.eql Dog // Nope: expected Animal to eql Dog
dog.constructor.should.eql Animal
animal.should.be_a Animal
dog.should.be_a Animal
// dog.should.be_a Dog // Nope! We severed the original prototype pointer and now point to Animal!
dog.should.be_an_instance_of Animal
dog.should.be_an_instance_of Dog
(animal instanceof Dog).should.be_false
end
it 'should behave such that child inherits methods and instance variables defined in parent'
animal.whoAmI().should.match /I am Onyx.*/
dog.whoAmI().should.match /Sebastian.*/
animal.should.respond_to 'whoAmI'
dog.should.respond_to 'whoAmI'
dog.should.have_prop 'name'
end
it 'should behave such that methods and instance variables added to child are NOT available to parent'
dog.bark().should.match /Ruff Ruff/i
dog.should.have_property 'breed'
dog.should.respond_to 'bark'
// animal.should.have_prop 'breed' // Of course not!
// animal.should.respond_to 'bark' // Of course not!
end
it 'should behave such that reference variables on the parent are "staticy" to all child instances'
dog.arr.should.eql([1,2,3])
dog.arr.push(4)
dog.arr.should.eql([1,2,3,4])
spike = new Dog("Spike", "Pitbull")
spike.arr.should.eql([1,2,3,4])
spike.arr.push(5)
rover = new Dog("Rover", "German Sheppard")
spike.arr.should.eql([1,2,3,4,5])
rover.arr.should.eql([1,2,3,4,5])
dog.arr.should.eql([1,2,3,4,5])
end
end
describe 'Combination Inheritance Solves Static Prototype Properties Issue'
it 'should maintain separate state for each child object'
child_1 = new Child("David", 21)
child_2 = new Child("Peter", 32)
child_1.arr.push(999)
child_2.arr.push(333)
child_1.arr.should.eql([1,2,3,999])
child_2.arr.should.eql([1,2,3,333])
child_1.getAge().should.eql 21
child_1.should.be_a Parent
end
end
describe 'Prototypal Inheritance'
it 'should inherit properties from parent'
person.toString().should.match /Original toString.*/i
person.password.should.eql 'secret'
joe = helper.inherit(person)
joe.password.should.eql 'secret'
joe.password = 'letmein'
joe.password.should.eql 'letmein'
person.password.should.eql 'secret'
end
end
describe 'Parisitic Combination Inheritance'
it 'should use inheritPrototype (to call parent constructor once) and still work as expected'
sub = new SubType("Nicholas Zakas", 29)
sub.toString().should.match /.*Nicholas Zakas/
sub.getAge().should.eql 29
charlie = new SubType("Charlie Brown", 69)
charlie.arr.should.eql([1,2,3])
charlie.arr.push(999)
charlie.arr.should.eql([1,2,3,999])
sub.arr.should.eql([1,2,3])
sub.should.be_an_instance_of SubType
charlie.should.be_an_instance_of SubType
(sub instanceof SubType).should.eql true
(sub instanceof Parent).should.eql true
end
end
describe 'Functional Durable Inheritance'
it 'should hide private variables'
sup = new super_func( {name: "Superfly Douglas", age: 39, foo: "foo", bar: "bar"} )
sup.getName().should.eql 'Superfly Douglas'
sup.name.should.be_undefined
sup.getAge().should.eql 39
sup.age.should.be_undefined
sup.getFoo().should.eql 'foo'
sup.foo.should.be_undefined
end
it 'should create a descendent object that inherits properties while maintaining privacy'
sub = new sub_func( {name: "Submarine", age: 1, foo: "food", bar: "barfly"} )
sub.getName().should.eql 'Submarine'
sub.name.should.be_undefined
sub.getAge().should.eql 1
sub.age.should.be_undefined
sub.getFoo().should.eql 'food'
sub.foo.should.be_undefined
sub.getBar().should.eql 'barfly'
sub.bar.should.be_undefined
sub.coolAugment().should.match /.*fresh new perspective.*/
//sub.should.be_an_instance_of super_func NOPE!
//sub.should.be_an_instance_of sub_func NOPE!
sub.should.be_an_instance_of Object
end
end
end
Thanks all! Oh, and if you want to check out my essay/book I'd love to get feedback:
TDD JavaScript at GitHub repo
See How to "properly" create a custom object in JavaScript? for a summary. (Might as well link it, since I wasted so much time typing it out!)
this:
Dog.prototype = new Animal();
would generally be avoided. You see it in example/tutorial code, but it's a horrible mess because it's basing a class on an instance, and an instance constructed in a faulty way: name is undefined. Any more complicated constructor is going to get upset at that sort of thing.
Object.prototype.inherit=
Is a better approach for constructing, but prototyping anything into Object is considered very poor taste. It runs the risk of messing up use of objects as trivial maps and breaking other code. You can put this helper function elsewhere, eg. Function.prototype.subclass.
prototype.constructor
Personally I would tend to avoid, because constructor has a special meaning in JavaScript (as implemented in Firefox and some other browsers; not IE's JScript), and that meaning is not what constructor does here nor what you would expect any such property to do; it's confusing and almost always best avoided. So if including a link to the constructor function in the instance in a class system I would prefer to name it something else.
A co-worker at my previous company developed a library to do java like inheritance http://www.uselesspickles.com/class_library/. I think it's sexier than Rajendra's suggestions, syntax looks cleaner.
I wrote an article that demonstrates different ways to approach it, but making sure that the known bad practices are avoided. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html, this is if you don't want to download a library but just want to copy paste some code that you can improve to do what you need.
There's an interesting pattern worth mentioning here: a JavaScript constructor may return any object (not necesserily this). One could create a constructor function, that returns a proxy object, that contains proxy methods to the "real" methods of the "real" instance object. This may sound complicated, but it is not; here is a code snippet:
var MyClass = function() {
var instanceObj = this;
var proxyObj = {
myPublicMethod: function() {
return instanceObj.myPublicMethod.apply(instanceObj, arguments);
}
}
return proxyObj;
};
MyClass.prototype = {
_myPrivateMethod: function() {
...
},
myPublicMethod: function() {
...
}
};
The nice thing is that the proxy creation can be automated, if we define a convention for naming the protected methods. I created a little library that does exactly this: http://idya.github.com/oolib/
I've got at least half a dozen implementations of various inheritance patterns lying around in my dev/web/stuff folder, but they are mostly toys.
What I actually sometimes use is the following thin wrapper over JavaScript's default pseudo-class-based approach to make inheritance easier:
Function.prototype.derive = (function() {
function Dummy() {}
return function() {
Dummy.prototype = this.prototype;
return new Dummy;
};
})();
Example code:
function Pet(owner, type, name) {
this.owner = owner;
this.type = type;
this.name = name;
}
Pet.prototype.toString = function() {
return this.owner + '\'s ' + this.type + ' ' + this.name;
};
function Cat(owner, name) {
Pet.call(this, owner, 'cat', name);
}
Cat.prototype = Pet.derive();
var souris = new Cat('Christoph', 'Souris');
Another interesting one is the following, which automatically adds factory methods to a proper prototypal approach:
var Proto = new (function() {
function Dummy() {}
this.clone = function() {
Dummy.prototype = this;
return new Dummy;
};
this.init = function() {};
this.create = function() {
var obj = this.clone();
this.init.apply(obj, arguments);
return obj;
};
});
Example code:
var Pet = Proto.clone();
Pet.init = function(owner, type, name) {
this.owner = owner;
this.type = type;
this.name = name;
};
Pet.toString = function() {
return this.owner + '\'s ' + this.type + ' ' + this.name;
};
Cat = Pet.clone();
Cat.init = function(owner, name) {
Pet.init.call(this, owner, 'cat', name);
};
// use factory method
var filou = Cat.create('Christoph', 'Filou');
// use cloning (the proper prototypal approach)
var red = filou.clone();
red.name = 'Red';
You've already seen my implementation of classes.
Late to the party here but I have 2 points to make.
1) Please do not inform people to inherit through creating supertype objects. This is considered bad practice for a few reason. Firstly, its a principle mistake. You are instantiating objects just to use their methods and not doing anything with the instance per se. The right way to have done this is to use the Object.prototype.inherit method. In addition, this method forces you to leave the supertype constructor function argument empty, which may invoke an error under strict circumstances.
2) You forgot to mention the constructor stealing pattern.
function Supertype(name){
this.name=name;
this.sayName = function(){console.log(this.name);};
}
function Subtype(name){
//inherit by using (stealing) supertype constructor function
Supertype(name);
// child specific properties
//
}

What techniques can be used to define a class in JavaScript, and what are their trade-offs?

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();

Categories

Resources