Related
This is sort of a follow up of from this question: Python like inheritance for JavaScript
But I phrased it wrong and made it seem like I wanted classical inheritance in JavaScript when I just wanted to figure out how to do it similarly to Python.
This is what I have so far but it isn't working as I would like it to.
var util = require("util")
function FirstClass() {
this.name = "First Class";
}
FirstClass.prototype.sayName = function(){
this.callFunction("some_function", "hello")
}
FirstClass.prototype.callFunction = function(){
var func = arguments[0];
var args = Array.prototype.slice.call(arguments).slice(1, arguments.length)
if (this[func] !== undefined){
this[func].apply(null, args);
}
}
function SubClass(){}
util.inherits(SubClass, FirstClass)
SubClass.prototype.some_function = function(msg){
console.log(msg, this.name) // "hello undefined"
}
var sub_class = new SubClass();
sub_class.sayName();
When I try sub_class.sayName() It calls correctly and inherited sayName right, but when I try using the this keyword to show the name it doesn't work and prints undefined next to 'hello', so how would I fix it so it will show 'hello FirstClass'?
I was thinking this have all the variables and objects that FirstClass has since it inherits from it but it doesn't. Is that how prototypal inheritance is suppose to work? If so is there any way I can view/change parent variables from the child class?
I've tried looking up prototypal inheritance for JavaScript to figure it out but I'm not quite grasping the concept since I'm use to classical inheritance. Does anyone know how to inherit from the parent class and change it's variables from a child class?
Also if anyone has a good link to look at so I can understand prototypal inheritance better for future references that would be great.
You are missing this part:
function SubClass(){
FirstClass.apply(this);
}
This would be the equivalent to a super invocation in traditional class inheritance.
Your problem lies here: this[func].apply(null, args);
It should read: this[func].apply(this, args);
Here is a simplified example of how to inherit and extend a class. I very highly recommend checking Javascript Design Patterns for much better examples of how to create Classes with inheritance.
Now, as I was not familiar with what util was supposed to be doing, this example demonstrates how to achieve the result with native JS and no helpers:
JSFiddle here: http://jsfiddle.net/YAj5R/
function FirstClass() {
this.name = "First Class";
}
FirstClass.prototype.sayName = function () {
this.callFunction("some_function", "hello")
}
FirstClass.prototype.callFunction = function () {
var func = arguments[0];
var args = Array.prototype.slice.call(arguments).slice(1, arguments.length)
if (this[func] !== undefined) {
this[func].apply(this, args);
}
}
function SubClass() {
var parent = new FirstClass();
// this is lightweight example of an "extend" method
for(var attr in parent) {
// if this subclass has not over-written an attr,
// copy the attributes of FirstClass to SubClass
if(!this[attr]) {
this[attr] = parent[attr];
}
}
return this;
}
SubClass.prototype.some_function = function (msg) {
console.log(msg, this.name);
}
var sub_class = new SubClass();
sub_class.sayName();
In Javascript, it seems like using property accessors is not all that common (unlike in other OO languages such as Java for example).
If I have a Person object with a name, defined as
function Person(name) {
this.name = name;
}
A person's name is not going to change, but I do want to be able to access it when needed, so I could do something like:
function Person(name) {
var name = name;
this.getName = function() {
return name;
}
}
Even in a dynamic language, I think the principles of using getters and setters apply the same way they do to statically typed OO languages (e.g. encapsulation, adding validation, restricting access, etc)
This question may get closed as subjective, but I'm curious as to why this behavior doesn't appear more often (e.g. Java developers would go crazy if everything was public).
Is there a "standard" way to do this in javascript? I've seen Object.defineProperty, but not all browsers support that.
Javascript has intercept-able property accessors:
http://ejohn.org/blog/javascript-getters-and-setters/
IMHO this is a far better solution to enforce the Uniform Access Principle than Java's more strict explicit getters, but that is also part of the simplicity and inflexibility of that language (Groovy for instance allows for similar interception).
I know my thoughts on the subject.
Getters and setters are evil.
Wait! Really! Bear with me a moment and let me explain.
Just using a method to get and set a value is .. well .. kinda pointless. It doesn't protect, not really, and what you put in is what you get out.
On the other hand, I'm rather fond of methods that put information in, then get information back out. BUT here is the magic part! It isn't the same information. Not directly.
function Person(name) {
this.getFullName = function() {return this.firstName + " " + this.lastName;};
this.setBirthday = function(date) { this.birthday = date; };
this.getAge = function() { /* Return age based on the birthday */ };
this.isOfLegalDrinkingAge function() { /* do your math here too */ };
}
But most of the time I'm just shoving static data in and getting static data out. What is the point of hiding it behind getters and setters?
As a secondary reason, dealing with the DOM and most host objects, you set properties. You don't play with getters and setters. Not using them fits the rest of the 'flavor' of what JS coders do.
I think the answer is that emulating classes in javascript is not the common practice, because the language is actually prototypal.
Although it is possible to create class like structures (as in your example), they are not really like java classes, and as a programmer, you end up fighting with the nuances.
If however, you embrace the prototypal nature of javascript, you are rewarded by a different, yet cohesive, and simple structure for the language.
It is not necessary to use getters and setters with prototypal structure, as you can simply set an object by, well, setting it to a value, and get it by, calling it as a value.
Javascript does not force you to write structured code, and does not stop you from doing so. I think the culture that has grown up around javascript has developed a good coding style, that is perfectly valid, and different from any other language I use.
I know this answer is not definitive, and conclusive, but hopefully there are some ideas in there that help you to find the anser you are looking for.
I apologize if I dont understand the question correctly, but self executing functions are one way to make members public/private
var Person = function(){
var _name = "Roger",
self = { getName : function (){ return _name; }};
return self;
}()
You can then access Person.getName() from anywhere , but not set _name.
This is what I used for local fields:
TYPE_DEFAULT_VALUE= {
number: 0,
string: "",
array: [],
object: {},
};
typeOf = function (object) {
if (typeof object === "number" && isNaN(object))
return NaN;
try {
return Object.prototype.toString.call(object).slice(8, -1).toLowerCase();
}
catch(ex) {
return "N/A";
};
};
getAccessor = function(obj, key, type, defaultValue) {
if (defaultValue === undefined)
defaultValue = TYPE_DEFAULT_VALUE[type] === undefined ? null : TYPE_DEFAULT_VALUE[type];
return {
enumerable: true,
configurable: true,
get: function () {
if (obj[key] === undefined)
obj[key] = defaultValue;
return obj[key];
},
set: function (value) {
if (typeOf(value) === type)
obj[key] = value;
},
};
}
LocalFields = function (fields, object) {
/**
* field properties
* {
* type: [ required ] ( number | string | array | object | ... ),
* defaultValue: [ optional ]
* }
*/
if (! fields)
throw "Too few parameters ...";
if (! object)
object = this;
var obj = this;
var fieldsAccessor = {};
for(key in fields){
field = fields[key];
fieldHandler = key[0].toUpperCase() + key.substr(1);
if(! field.type)
throw "Type not set for field: " + key;
fieldsAccessor[fieldHandler] = getAccessor(obj, fieldHandler, field.type, field.defaultValue)
}
Object.defineProperties(object, fieldsAccessor);
}
Now for each Class I can just call something like:
Person = function(){
new LocalFields({
id: { type: "number" },
name: { type: "string" },
}, this);
}
And then like VS getter and setter you'll call:
var alex = new Person();
alex.Name = "Alex Ramsi";
console.clear();
console.info(alex.Name);
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I'm sick of seeing dozens of different ways of doing object oriented programming in Javascript. Can anyone just tell me which technique I should use considering I want to work on a large scale project and I want my code to be future proof?
These are just a few quick guidelines I've come up with, if anyone else has anything meaningful to add, I've set this answer as a community wiki so it should be easy enough for you to edit.
Namespace your objects to ensure they will never conflict with third party JavaScript libraries.
window['Andrew']['JS'] = {
addEvent: function(el,evName) {/*Stuff*/},
Rectangle: function(width,height) {/*Stuff*/}
};
So then you would create a rectangle object by using:
var myRect = new Andrew.JS.Rectangle(14,11);
And then your code will never interfere with, or be interfered by anybody else's Rectangle.
Use a consistent naming strategy, specifically:
Object names should be capitalized, everything else (variables, functions) should begin with a lower case character i.e.
var myRect = new Andrew.JS.Rectangle(14,11);
document.write(myRect.getArea());
Ensure everything is meaningful, i.e. verbs for methods, nouns + adjectives for parameters.
Make sure all methods and parameters are relevant to the object they belong to. e.g.
In this example, the area of the rectangle can be converted to square feet using the method inSquareFeet().
myRect.getAreaObject().inSquareFeet();
Make sure inSquareFeet is a method of the object returned by getAreaObject() and not a method of Andrew.JS.Rectangle
Use constructors, or more specifically, try as hard as possible to make sure that an object doesn't need any further initialization to be used once it has been constructed, so instead of:
var Person = function()
{
this.name = "";
this.sayHello = function ()
{
alert(this.name + " says 'Hello!'");
return this;
}
}
var bob = new Person();
bob.name = "Bob Poulton";
bob.sayHello();
try:
var Person = function(name)
{
this.name = name;
this.sayHello = function ()
{
alert(this.name + " says 'Hello!'");
return this;
}
}
var bob = new Person("Bob Poulton");
bob.sayHello();
I always use John resig's:
http://ejohn.org/blog/simple-javascript-inheritance/
It's simple and doesn't require any frameworks to function.
Because you are working on a large scale project i would suggestion a javascript framework like mootools http://mootools.net/.
It has a good class and inheritance structure.
My ideal Object for OOP is like using an Instance method with prototypes:
Example:
var Users = function()
{
var _instance;
this.prototype.getUsername = function(){/*...*/}
this.prototype.getFirstname = function(){/*...*/}
this.prototype.getSecurityHash = function(){/*...*/}
/*...*/
/*Static Methods as such*/
return { /*Return a small Object*/
GetInstance : function()
{
if(_instance == null)
{
_instnance = new Users(arguments);
}
return _instnance; //Return the object
},
New: function()
{
_instnance = null; //unset It
return this.GetInstnace(arguments);
}
}
}
Then I would always use like:
Firstname = Users.GetInstance('Robert','Pitt').getFirstname();
Username = Users.GetInstance().getUsername(); //Returns the above object.
Me = Users.New('Robert',null); //Deletes the above object and creates a new instance.
Father = Users.New('Peter','Piper'); //New Object
Me.AddFather(Father); //Me Object.
And that's the kind of road i go down when it comes to building a JavaScript OO Style architecture.
just for your information, i think YUI provides few great tutorials on this topic
//Create and define Global NameSpace Object
( function(GlobalObject, $, undefined)
{
GlobalObject.Method = function()
{
///<summary></summary>
}
GlobalObject.Functionality = {};
}) (GlobalObject = GlobalObject || {}, jQuery);
//New object for specific functionality
( function(Events, $, undefined)
{
//Member Variables
var Variable; // (Used for) , (type)
// Initialize
Events.Init = function()
{
///<summary></summary>
}
// public method
Events.PublicMethod = function(oParam)
{
///<summary></summary>
///<param type=""></param>
}
// protected method (typically define in global object, but can be made available from here)
GlobalObject.Functionality.ProtectedMethod = function()
{
///<summary></summary>
}
// internal method (typically define in global object, but can be made available from here)
GlobalObject.InternalMethod = function()
{
///<summary></summary>
}
// private method
var privateMethod = function()
{
///<summary></summary>
}
}) (GlobalObject.Funcitonality.Events = GlobalObject.Funcitonality.Events || {}, jQuery )
// Reusable "class" object
var oMultiInstanceClass = function()
{
// Memeber Variables again
var oMember = null; //
// Public method
this.Init = function(oParam)
{
oMember = oParam;
for ( n = 1; i < oMemeber.length; i += 1 )
{
new this.SubClass.Init(oMember[i]); // you get the point, yeah?
}
}
this.Subclass = function()
{
this.Init = function() { }
}
}
The strength to this is that it initializes the Global object automatically, allows you to maintain the integrity of your code, and organizes each piece of functionality into a specific grouping by your definition.
This structure is solid, presenting all of the basic syntactical things you would expect from OOP without the key words.
There are even some ingenious ways to set up interfaces as well. If you choose to go that far, a simple search will give you some good tutorials and tips.
Even setting up intellisense is possible with javascript and visual studio, and then defining each piece and referencing them makes writing javascript cleaner and more manageable.
Using these three methods as needed by your situation helps keep the global namespace clean, keep your code organized and maintains separation of concerns for each object.. if used correctly. Remember, Object Oriented Design is of no use if you don't utilize the logic behind using objects!
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
return {
publicMethod: function() { alert(iAmAPrivateVariable); },
publicVariable: bar()
}
}
//usage
var thing = foo()
This is a functional approach, and has a great deal more going for it (such as encapsulation) then anything else you are going to see
In a general way, you shouldn't be doing OO in javascript, it isn't that great a language for it for a great many reasons. Think scheme with squiggly brackets and semi-colons, and you will start writing the language like the pros do. That being said, sometime OO is a better fit. In those cases, the above is typically the best bet
to bring inheritance into the mix
function parent() {
return { parentVariable: 2 };
}
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
me = parent();
me.publicMethod = function() { alert(iAmAPrivateVariable); };
me.publicVariable = bar();
return me;
}
This makes things a tad more complected, but accomplishes the desired end result while still taking a functional approach to OO concepts (in this case, using decorator functions instead of real inheritance). What I like about the whole approach is we are still really treating objects the way they are intended to be in this kind of language -- a property bag you can attach stuff to at will.
Another note is this is wildly different then what you will see most of the time in most of the jobs you will ever work at, and often is very hard to explain a) what is going on, and b) why it is a good idea to coworkers.
I use such a pattern and recommend to you to use it too:
function Person(firstname, lastname, age)
{
var self = this;
var _ = {};
// Private members.
var firstname = firstname;
var lastname = lastname;
var age = age || 'unknown';
// Private methods.
function first_letter_to_uppercase(str) {
return str.charAt(0).toUpperCase() + str.substr(1);
}
// Public members and methods.
_.get_age = function()
{
return age;
}
_.get_name = function()
{
return first_letter_to_uppercase(firstname) + ' ' +
first_letter_to_uppercase(lastname);
}
return _;
}
var p = new Person('vasya', 'pupkin', 23);
alert("It's " + p.get_name() + ', he is ' + p.get_age() + ' years old.')
You can try with a simple, usefull and quick object:
var foo = {
foo1: null,
foo2: true,
foo3: 24,
foo4: new Array(),
nameOfFunction1: function(){
alert("foo1");
},
nameOfFunction2: function(){
alert("foo2");
},
}
To use this, you have to create an instance of this object and use like a object in java:
foo.nameOfFunction2();
Also you can check this link to other solution: http://www.javascriptkit.com/javatutors/oopjs.shtml
I hope that answer your question.
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 have the following code that creates two objects (ProfileManager and EmployerManager) where the object EmployerManager is supposed to inherit from the object ProfileManager.
However, when I do alert(pm instanceof ProfileManager); it returns false.
function ProfileFactory(profileType) {
switch(profileType)
{
case 'employer':
return new EmployerManager();
break;
}
}
function ProfileManager() {
this.headerHTML = null;
this.contentHTML = null;
this.importantHTML = null;
this.controller = null;
this.actions = new Array();
this.anchors = new Array();
}
ProfileManager.prototype.loadData = function(action, dao_id, toggleBack) {
var step = this.actions.indexOf(action);
var prv_div = $('div_' + step - 1);
var nxt_div = $('div_' + step);
new Ajax.Request(this.controller, {
method: 'get',
parameters: {action : this.actions[step], dao_id : dao_id},
onSuccess: function(data) {
nxt_div.innerHTML = data.responseText;
if(step != 1 && !prv_div.empty()) {
prv_div.SlideUp();
}
nxt_div.SlideDown();
for(i = 1; i <= step; i++)
{
if($('step_anchor_' + i).innerHTML.empty())
{
$('step_anchor_' + i).innerHTML = this.anchors[i];
}
}
}
}
)
}
EmployerManager.prototype.superclass = ProfileManager;
function EmployerManager() {
this.superclass();
this.controller = 'eprofile.php';
this.anchors[1] = 'Industries';
this.anchors[2] = 'Employer Profiles';
this.anchors[3] = 'Employer Profile';
this.actions[1] = 'index';
this.actions[2] = 'employer_list';
this.actions[3] = 'employer_display';
}
var pm = new ProfileFactory('employer');
alert(pm instanceof ProfileManager);
BTW, this is my very first attempt at Object-Oriented JavaScript, so if you feel compelled to comment on the stupidity of my approach please feel free to do so, but offer suggestions on how to approach the problem better.
I've been using something similar to Dean Edward's Base.js model.
http://dean.edwards.name/weblog/2006/03/base/
Prototype supports (mimicing) class inheritance via the Object.extend() function.
However, it could be argued that trying to impose class-based inheritance on a language which doesn't support classes is an example of "when you only have a hammer, the whole world looks like a nail".
Thanks for all of the comments. However, the solution to the problem was found in making this change to the declaration of the EmployerManager:
function EmployerManager() {
this.controller = 'eprofile.php';
this.anchors = new Array('Industries', 'Employer Profiles', 'Employer Profile');
this.actions = new Array('index', 'employer_list', 'employer_display');
}
EmployerManager.prototype = new ProfileManager;
Apparently JavaScript supports two different types of inheritance, function based and prototype based. The function based version is what I originally posted but could not make work because the EmployerManager could not see the loadData method that was part of ProfileManager's prototype.
This new example is prototype based and works now. EmployerManager is now an instance of ProfileManager.
In your code, pm is an instance of EmployerManager that has a superclass of ProfileManager. That seems backwards to me. Shouldn't ProfileManager have a superclass of EmployerManager?
I just wanted to interject that while JavaScript is an object oriented language, it does not have many of the features common in other popular OO languages. Conversely, it also has many features that other popular OO languages do not.
As you have already discovered inheritance is managed via prototype objects, rather than by class inheritance. However, the prototype object is not examined when using the "instanceof" operator. This means that JavaScript does not support polymorphism. At least not out of the box.
You can find libraries that will make JavaScript conform to the model of OOP that you're used to; if you're under the gun this might be the best solution. (Although no library is ever going to make a JavaScript object polymorphic when examined using "instanceof"; an isInstanceOf function would probably be necessary.) Or you could choose another language which does conform to that model of OOP, but you're probably working in a browser, so that's obviously not an option. Or you could answer the question, "how can I solve my problem without polymorphism?"
You should note that the same question has been asked (by me). Check out the answers on that post.
You can use new or Object.create to achieve classical inheritance
function A(){
B.call(this);
}
function B(){
}
//there are 2 ways to make instanceof works
//1. use Object.create
A.prototype = Object.create(B.prototype);
//2. use new
//A.prototype = new B();
console.log(new A() instanceof B); //true
//make instanceof works
EmployerManager.prototype = Object.create(ProfileManager.prototype);
//add other prototype memebers
EmployerManager.prototype.superclass = ProfileManager;
console.log(new EmployerManager() instanceof ProfileManager); //true