in Javascript a "class" is "function", function body is the "constructor"
function className() { // constructor } // create an instance of className var obj = new className(); // Object is predefined new Object(); // Use literal notation: var obj = { propData: 100, propString: "hello world", propArray: ["a", "bbb", "", "jajajaja"], methodA: function () { ... }, methodB: function () {... }, multilineString: '<div class="pp_pic_holder"> \ <div class="ppt"> </div> \ <div class="pp_top"> \ <div class="pp_left"></div>'; };
This is the fastest way to creat a global object. The literial notation is not a "class", it can only be used to create one instance.
var Me = { name: "Robert Mao", sex: "M", say: function() { alert("hello world"); } }; // works Me.say(); // ERROR: Me is not a constructor var me = new Me(); Me.run = function() { alert("I can run"); } Me.run(); // WRONG!!! Me.prototype.runMore = function() {}
factory method actually return an object created by literial notation. it can be used to create some "private" member of a object.
function createObject(name) { var privateName = name || "I am private name"; var privateMethod = function () { return "result of private"; } return { publicName: "I am public name", publicMethod: function () { alert("privateName is " + privateName + ", privateMethod called: "+ privateMethod()); } } } var obj2 = createObject("robert"); obj2.publicMethod();
function Person(name) { var privateName = name || "I am private"; var privateMethod = function() { return privateName; } this.publicName = "I am public"; this.publicMethod = function() { alert(privateName + " get from public method!"); } } var obj3= new Person("robert"); obj3.publicMethod();
(public) class member
function Person(name) { // access the "private" members // is actually add member to this instance only this.method = function() { } } // will not able access "private" members defined in the constructor // extend all the instance of such class and Impact to the class inherit function.prototype.newMethod = function() { }
function A() { this.method = function() { } } function B() { var base = A; // call base constructor base(); } // inheritance B.prototype = new A(); var obj = new B(); // ok inherit from class A obj.method();
method overwrite
function B() { this.method = function() { // overwrite the "method" defined in base class } }
this.method = function() { // overwrite the "method" defined in base class this.__proto__.method.call(this); } // sets the context to the body element // with the current arguments myfunct.apply(document.body, arguments);
using prototype to create such method, it will looks more neat:
function A() { } A.prototype.method = function() { } function B() { } B.prototype = new A(); B.prototype.method = function() { // call old "method" defined in class A A.prototype.method.call(this); }
If you are creating a class that might be subclassed later, it is best to stick to one of the fully exposed patterns. var Book = function(newIsbn) { implements Publication
// Private attributes. var isbn;
// Private method, not possible to override it function checkIsbn(isbn) { }
// Privileged methods: can access private vars this.getIsbn = function() { return isbn; }; this.setIsbn = function(newIsbn) { if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.'); isbn = newIsbn; };
// Constructor code. this.setIsbn(newIsbn);
};
// Public, non-privileged methods. Book.prototype = { display: function() { } };
By putting the private members in a closure, you are ensuring that they will never be used outside of the object. You have complete freedom to change the implementation details without breaking anyone else's code.
var Book = (function() { // Private static attributes. var numOfBooks = 0; // Private static method. function checkIsbn(isbn) { ... } // Return the public constructor. return function(newIsbn, newTitle, newAuthor) { // implements Publication // Private attributes. var isbn, title, author; // Privileged methods. this.getIsbn = function() { return isbn; }; this.setIsbn = function(newIsbn) { if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.'); isbn = newIsbn; }; this.getTitle = function() { return title; }; this.setTitle = function(newTitle) { title = newTitle || 'No title specified'; }; this.getAuthor = function() { return author; }; this.setAuthor = function(newAuthor) { author = newAuthor || 'No author specified'; }; // Constructor code. numOfBooks++; // Keep track of how many Books have been instantiated // with the private static attribute. if(numOfBooks > 50) throw new Error('Book: Only 50 instances of Book can be created.'); this.setIsbn(newIsbn); this.setTitle(newTitle); this.setAuthor(newAuthor); } })(); // function execute immediately, as soon as the code is loaded (not when the Book constructor is called). // The result of that execution is another function, which is returned and set to be the Book con- // structor. When Book is instantiated, this inner function is what gets called; // Public static method. Book.convertToTitleCase = function(inputString) { }; // Public, non-privileged methods. Book.prototype = { display: function() { ... } };
To create a class that inherits from Person, it gets a little more complex:
function Author(name, books) { Person.call(this, name); // Call the superclass's constructor in the scope of this. this.books = books; // Add an attribute to Author. } Author.prototype = new Person(); // Set up the prototype chain. Author.prototype.constructor = Author; // Set the constructor attribute to Author. Author.prototype.getBooks = function() { // Add a method to Author. return this.books; }; /* Extend function. */ function extend(subClass, superClass) { var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; }
/* Clone function. */ function clone(object) { function F() {} F.prototype = object; return new F; }
Prototypal inheritance is very memory-efficient. Because of the way prototype chain reads members, all cloned objects share a single copy of each attribute and method, until those attrib- utes and methods are written to directly on the cloned object. Contrast this with the objects created using classical inheritance, where each object has a copy of every attribute (and pri- vate method) in memory.
var Person = { name: 'default name', getName: function() { return this.name; } }; /* Author Prototype Object. */ var Author = clone(Person); Author.books = []; // Default value. Author.getBooks = function() { return this.books; }
The methods and attributes of this clone can then be overridden. You can change the default values given by Person, or you can add new attributes and methods. That creates a new prototype object, which you can then clone to create new Author-like objects:
var author = []; author[0] = clone(Author); author[0].name = 'Dustin Diaz'; author[0].books = ['JavaScript Design Patterns']; author[1] = clone(Author); author[1].name = 'Ross Harmes'; author[1].books = ['JavaScript Design Patterns']; author[1].getName(); author[1].getBooks();