OOP
- Objects are also associative arrays (hashes).
- Object members can be accessed using array syntax.
obj.data obj.foo()
obj['data'] obj['foo']()
JSON
myObj = { name1:value1, name2:value2, ... }
- JavaScript Object Notation
- A subset of the JavaScript object literal notation
- Useful for sending structured data; simpler and faster than using XML
- Can be used for CSI (client-side includes)
- The same syntax is used for associative-array literals.
var myObj = {
myInt: 1,
myArray1: ["yellow", "green"],
myArray2: {"lemon":"yellow", "lime":"green"}
}
Object to string
var myJSONText = JSON.stringify(myObject);
String to object
var myObject = eval('(' + myJSONtext + ')'); // Fast
var myObject = JSON.parse(myJSONtext); // Faster (if natively supported) and safer
Object literals
var myObj = {
data: 1,
foo: function() {...}
};
- JavaScript object literal notation
- Encapsulated by curly brackets with zero or more property and value pairs, separated by commas
- Each property and value is separated by a colon
- Property names can be identifiers, strings, or numbers
- Values can be strings, numbers, functions, or other objects
var myObj = {
// Properties
myInt: 1,
myStr: "",
myBool: false,
myArray1: [],
myArray2: ["yellow", "green"],
myArray3: {0:"yellow", 1:"green"},
myArray4: {"lemon":"yellow", "lime":"green"},
// Methods
foo: function() { return this.myInt; },
bar: function(args) { ... }
}
var x = myObj.foo();
var y = myObj["foo"]();
Object templates
function MyObject() {
this.data = 1;
this.foo = function() {...};
}
- aka object constructors, constructor functions, constructors
- Functions can be used as a template for new objects
- An object template is often referred to as a class
function MyObject(args) {
// Properties
this.myInt = 1;
this.myArray = new Array();
// Methods
this.foo = function() { return this.myInt; }
this.bar = function(args) { ... }
}
# Instantiating the Object
var myObj = new MyObject();
var x = myObj.foo();
Instantiating objects
- The following are equivalent:
Object literal
// Object literal
var myObj = {
num: 30,
foo: function() {}
}
Object template
function MyObject() {
this.num = 30;
this.foo = function() {}
}
var myObj = new MyObject();
// Anonymous object template
var myObj = new function() { ... }
// Named object template (easier to debug when it's not anonymous)
var myObj = new function MyObject() { ... }
Adding properties and methods on-the-fly
var myObj = new function() {};
myObj.num = 30;
myObj.foo = function() {};
var myObj = new Object(); ...
new operator
- When using the new operator, parentheses are optional when calling an object template with no arguments
function MyObject() {...}
obj1 = new MyObject();
obj2 = new MyObject;
- The difference between an object template (class) and a regular function is that an object template is called using the "new" keyword, which creates a new instance of the object template (class)
- If an object template is called without the "new" keyword, it is run as a regular function, and "this" refers to the global object (which in browsers is the same as "window")
function MyObject() {
// If "new" was omitted, correct the problem
if (!(this instanceof MyObject)) { return new MyObject(); }
...
}
function MyObject() {
// If "new" was omitted, raise an exception
if (!(this instanceof arguments.callee)) { throw Error("Constructor called as a function"); }
...
}
Properties
function MyObject() { // Access level Internal External
var a = 1; // Private a n/a
this.a = 1; // Public this.a obj.a
}
MyObject.prototype.a = 1; // Prototype this.a obj.a
MyObject.a = 1; // Static MyObject.a MyObject.a
Private
var myVar = 50;
- aka private variables
- Private properties can be accessed within a privileged or private method (without using
this).
- To access private data, the methods have to be defined within the same closure as the private data.
- Constructor parameters remain available as implicit private properties.
Public
this.data = 1;
- Public properties can be accessed within a public or privileged method using
this. - Public properties can be accessed externally using the name of the object instance.
Prototype
MyObject.prototype.data = 1;
- Added for each instance of the object, even those that have already been created
- Are not static
- Prototype properties can be accessed within a public or privileged method using
this. - Prototype properties can be accessed externally using the name of the object instance.
Static
MyObject.data = 1;
- Static properties can be accessed within a public, privileged, private, or static method using the name of the object template.
- Static properties can be accessed externally using the name of the object template.
Methods
function MyObject() { // Access level Internal External
function foo(){}; // Private foo() n/a
var foo = function(){}; // Private foo() n/a
this.foo = function(){}; // Privileged this.foo() obj.foo()
}
MyObject.prototype.foo = function(){}; // Public this.foo() obj.foo()
MyObject.foo = function() {}; // Static MyObject.foo() MyObject.foo()
Private
function foo1() {...} // Shorthand syntax
var foo2 = function() {...}
- aka private functions
- Private methods can be accessed within a privileged or private method (without using
this).
- Private methods can access private and static properties and methods.
- Private methods lack an implicit
thisvariable for accessing additional properties and methods
Privileged
this.methodName = function() {...};
- Privileged methods can be accessed within public or privileged methods using
this. - Privileged methods can be accessed externally using the name of the object instance.
- Privileged methods can access private, public, prototype, and static properties.
- Privileged methods can access private, public, privileged, and static methods.
- Unlike public methods, privileged methods are able to access private properties and methods, unless they're defined outside of the object template.
obj.methodName = function() {...}; // Defined externally; cannot access private properties and methods
Public
MyObject.prototype.foo = function() {...}
- Added for each instance of the object, even those that have already been created
- Are not static
- Public methods can be accessed within a public or privileged method using
this. - Public methods can be accessed externally using the name of the object instance.
- Public methods can access public, prototype, and static properties.
- Public methods can access public, privileged, and static methods.
- Public methods are unable to access private properties and methods.
Static
MyObject.foo = function() {...}
- Static methods can be accessed within a private, public, privileged, or static method using the name of the object template.
- Static methods can be accessed externally using the name of the object template.
- Static methods can only access static properties and methods.
Inheritance
function Parent() {}
function Child() {}
Child.prototype = new Parent(); // Specify that Child inherits from Parent
Child.prototype.constructor = Child; // Reset the constructor property; otherwise, instances
// of Child would have a constructor of Parent.
// Call an overridden parent method from within a child method, using the context of the child object. // Any parameters for the function go after "this". Parent.prototype.foo.call(this); // Parent method must be a public (prototype) method
Tricks to simplify inheritance
parent
// Define a makeshift "parent" property to abstract the name of the parent (note: "super" is a reserved word) Child.prototype.parent = Parent.prototype; ... this.parent.foo.call(this);
inheritsFrom
// Extend the Function object
Function.prototype.inheritsFrom = function(parentClass) {
this.prototype = new parentClass;
this.prototype.constructor = this;
this.prototype.parent = parentClass.prototype;
return this;
}
...
Child.inheritsFrom(Parent);
In-depth
Efficiency
- The following members are instantiated for each new object: private and public properties, private and privileged methods (i.e. non-static, non-prototype).
- Only one copy exists for static and prototype properties, and static and public (prototype) methods.
- When a prototype property is modified through an object instance, a new public property is created for that object instance (i.e. copy-on-write).
MyObject.prototype.data = 1; // Define prototype property obj.data = 2; // Create a public property for the modified value (if not already done) MyObject.prototype.data = 3; // Modify existing prototype property
- Public methods are more memory-efficient than privileged methods, but they force the use of public properties (rather than private ones), which makes them less robust (vulnerable to inappropriate external modification).
Private data
- To access private data, the methods have to be defined within the same closure as the private data.
- This also applies for accessing private methods.
- Private data is defined within an object template, cannot be accessed externally, and can only be accessed by methods defined within the object template.
- This helps avoid inappropriate use or modification of private data and methods.
Private methods
- Private methods lack an implicit
thisvariable (for accessing public and prototype properties, and public and privileged methods) - This is due to an error in the ECMAScript specification which causes
thisto be set incorrectly for inner functions
- Can't define an explicit
thisparameter or variable, sincethisis a reserved keyword, and in browsers there's already a defaultthisvariable that refers to thewindowobject - Could optionally store the value of
thisin a private property (_this,self,that, ...)
var _this = this; // Private methods can use "_this" as an alias for "this"
Public methods
- Public methods can be used as wrappers for privileged methods which can then access private properties and methods (so long as the privileged methods are defined within the object template).
this.innerFoo = function() {...}; // Privileged method
...
MyObject.prototype.foo = function() { return this.innerFoo(); } // Call the privileged method
Design patterns
Singleton pattern
var obj = new function() { ... } // Anonymous object template
var obj = new function MyObject() { ... } // Named object template (easier to debug)
function MyObject() { // Private object constructor
// If the constructor was not called by the getInstance method
if (MyObject.caller != MyObject.getInstance) {
throw new Error("There is no public constructor for MyObject.");
}
...
}
MyObject.__instance__ = null; // Static property
MyObject.getInstance = function() { // Static method
if (this.__instance__ == null) {
this.__instance__ = new MyObject();
}
return this.__instance__;
}
var obj = MyObject.getInstance(); // Get the singleton object
Resources URL:
notes/javascript/resources
Sources URL:
notes/javascript/sources