Javascript Object-Oriented Programming (coolshell)

Source: Internet
Author: User
Tags mozilla developer network

A colleague has been asking me about Javascript object-oriented things these two days. So, just write an article and let him see it, this article mainly aims to introduce Javascript object-oriented programming from a holistic perspective. (The written documents are too hasty. There should be some inaccuracy or errors. Please criticize and correct them)
This article is mainly based on ECMAScript 5 and aims to introduce new technologies. For compatibility, see the last section.

Preliminary Exploration
We know that the definition of variables in Javascript is basically as follows:

Copy codeThe Code is as follows:
Var name = 'chen hao ';;
Var email = 'haoel (@) hotmail.com ';
Var website = 'HTTP: // jb51.net ';

If you want to write an object, it will look like this:

Copy codeThe Code is as follows:
Var chenhao = {
Name: 'chen hao ',
Email: 'haoel (@) hotmail.com ',
Website: 'http: // jb51.net'
};

Then, I can access:

Copy codeThe Code is as follows:
// As a member
Chenhao. name;
Chenhao. email;
Chenhao. website;

// Hash map
Chenhao ["name"];
Chenhao ["email"];
Chenhao ["website"];

We know that Javascript Functions are like this:


Copy codeThe Code is as follows: var doSomething = function (){
Alert ('Hello World .');
};

So we can do this:

Copy codeThe Code is as follows: var sayHello = function (){
Var hello = "Hello, I'm" + this. name
+ ", My email is:" + this. email
+ ", My website is:" + this. website;
Alert (hello );
};

// Directly assign values, which is similar to the function pointer of C/C ++.
Chenhao. Hello = sayHello;

Chenhao. Hello ();

I believe these things are simple and everyone understands them. We can see that javascript Object functions are directly declared and directly assigned values. Dynamic Language of runtime.

There is also a more standardized way of writing:

Copy codeThe Code is as follows:
// We can see that the function is used as the class.
Var Person = function (name, email, website ){
This. name = name;
This. email = email;
This. website = website;

This. sayHello = function (){
Var hello = "Hello, I'm" + this. name + ", \ n" +
"My email is:" + this. email + ", \ n" +
"My website is:" + this. website;
Alert (hello );
};
};

Var chenhao = new Person ("Chen Hao", "haoel@hotmail.com ",
Http://jb51.net ");
Chenhao. sayHello ();

By the way, it is very easy to delete the attributes of an object:

1 delete chenhao ['email ']

The above examples show the following points:

Javascript data and member encapsulation is simple. No class is completely an object operation. Pure dynamic!
The this pointer in Javascript Functions is critical. If not, it is a local variable or a local function.
Javascript Object member functions can be declared temporarily during use, and a global function can be assigned directly.
Javascript member functions can be modified on the instance. That is to say, the same function name of different instances may not behave the same.
Property configuration-Object. defineProperty
Let's take a look at the following code:

Copy codeThe Code is as follows: // create an object
Var chenhao = Object. create (null );

// Set an attribute
Object. defineProperty (chenhao,
'Name', {value: 'chen hao ',
Writable: true,
Retriable: true,
Enumerable: true });

// Set multiple attributes
Object. defineProperties (chenhao,
{
'Email ': {value: 'haoel @ hotmail.com ',
Writable: true,
Retriable: true,
Enumerable: true },
'Website': {value: 'http: // jb51.net ',
Writable: true,
Retriable: true,
Enumerable: true}
}
);

The following describes what these attribute configurations mean.

Writable: whether the value of this attribute can be changed.
Retriable: Can the configuration of this attribute be changed.
Enumerable: can this attribute be stored in... In loop traversal or listing in Object. keys.
Value: the attribute value.
Get ()/set (_ value): get and set accessors.
Get/Set accessors
For get/set accessors, it means to replace value with get/set (which cannot be used together with value), for example:

Copy codeCode: var age = 0;
Object. defineProperty (chenhao,
'Age ',{
Get: function () {return age + 1 ;},
Set: function (value) {age = value ;}
Enumerable: true,
Retriable: true
}
);
Chenhao. age = 100; // call set
Alert (chenhao. age); // call get to output 101 (+ 1 in get );

Let's look at a more practical example -- using the existing property (age) to construct a new property (birth_year) through get and set ):

Copy codeThe Code is as follows:
Object. defineProperty (chenhao,
'Birth _ year ',
{
Get: function (){
Var d = new Date ();
Var y = d. getFullYear ();
Return (y-this. age );
},
Set: function (year ){
Var d = new Date ();
Var y = d. getFullYear ();
This. age = y-year;
}
}
);

Alert (chenhao. birth_year );
Chenhao. birth_year = 2000;
Alert (chenhao. age );

It seems a little troublesome to do this. You said, why don't I write it as follows:

Copy codeThe Code is as follows: var chenhao = {
Name: "Chen Hao ",
Email: haoel@hotmail.com ",
Website: "http://jb51.net ",
Age: 100,
Get birth_year (){
Var d = new Date ();
Var y = d. getFullYear ();
Return (y-this. age );
},
Set birth_year (year ){
Var d = new Date ();
Var y = d. getFullYear ();
This. age = y-year;
}

};
Alert (chenhao. birth_year );
Chenhao. birth_year = 2000;
Alert (chenhao. age );

Yes, you can, but with defineProperty (), you can:
1) set attributes such as writable, retriable, and enumerable.
2) dynamically add attributes to an object. For example, some html dom objects.

View object property Configuration
If you view and manage these configurations of an object, a program can output the attributes and configurations of the object:

Copy codeThe Code is as follows: // list object attributes.
Function listProperties (obj)
{
Var newLine = "<br/> ";
Var names = Object. getOwnPropertyNames (obj );
For (var I = 0; I <names. length; I ++ ){
Var prop = names [I];
Document. write (prop + newLine );

// Use the getOwnPropertyDescriptor function to list object property configurations.
Var descriptor = Object. getOwnPropertyDescriptor (obj, prop );
For (var attr in descriptor ){
Document. write ("..." + attr + ':' + descriptor [attr]);
Document. write (newLine );
}
Document. write (newLine );
}
}

ListProperties (chenhao );

Call, apply, bind, and this
This pointer of Javascript is similar to C ++/Java. Let's take a look at the example: (this example is very simple and I will not talk about it more)

Copy codeThe Code is as follows: function print (text ){
Document. write (this. value + '-' + text + '<br> ');
}

Var a = {value: 10, print: print };
Var B = {value: 20, print: print };

Print ('hello'); // this => global, output "undefined-hello"

A. print ('A'); // this => a, output "10-"
B. print ('B'); // this => B, output "20-B"

A ['print'] ('A'); // this => a, output "10-"

Let's take a look at call and apply. The difference between the two functions is that the parameters look different. The other is that the performance is different, and the performance of apply is much worse. (For performance, run the JSPerf command)

Copy codeThe Code is as follows: print. call (a, 'A'); // this => a, output "10-"
Print. call (B, 'B'); // this => B, output "20-B"

Print. apply (a, ['a']); // this => a, output "10-"
Print. apply (B, ['B']); // this => B, output "20-B"

However, after bind, The this pointer may be different, but Javascript is dynamic. Example

Copy codeThe Code is as follows: var p = print. bind ();
P ('A'); // this => a, output "10-"
P. call (B, 'B'); // this => a, output "10-B"
P. apply (B, ['B']); // this => a, output "10-B"

Inheritance and overloading
Through the above examples, we can actually inherit through Object. create (). Please refer to the following code. Student inherits from Object.

Copy codeThe Code is as follows: var Person = Object. create (null );

Object. defineProperties
(
Person,
{
'Name': {value: 'chen hao '},
'Email ': {value: 'haoel @ hotmail.com '},
'Website': {value: 'http: // jb51.net '}
}
);

Person. sayHello = function (){
Var hello = "<p> Hello, I am" + this. name + ", <br>" +
"My email is:" + this. email + ", <br>" +
"My website is:" + this. website;
Document. write (hello + "<br> ");
}

Var Student = Object. create (Person );
Student. no = "1234567"; // Student ID
Student. dept = "Computer Science"; // System

// Use the attributes of Person
Document. write (Student. name + ''+ Student. email +'' + Student. website + '<br> ');

// Use the Person Method
Student. sayHello ();

// Reload the SayHello Method
Student. sayHello = function (person ){
Var hello = "<p> Hello, I am" + this. name + ", <br>" +
"My email is:" + this. email + ", <br>" +
"My website is:" + this. website + ", <br>" +
"My student no is:" + this. no + ", <br>" +
"My temporary ent is:" + this. dept;
Document. write (hello + '<br> ');
}
// Call again
Student. sayHello ();

// View the attributes of Student (only no, dept, and sayHello with heavy loads)
Document. write ('<p>' + Object. keys (Student) + '<br> ');

In the general example above, we can see that the attributes in Person are not actually copied to Student, but we can access them. This is because Javascript uses delegation to implement this mechanism. In fact, this is Prototype, and Person is the Prototype of Student.

When our code requires an attribute, the Javascript engine first checks whether the current object has this attribute. If not, the system checks whether the Prototype object has this attribute and continues until it is found or until there is no Prototype object.

To prove this, we can use Object. getPrototypeOf () to verify:

Copy codeThe Code is as follows: Student. name = 'aaa ';

// Output aaa
Document. write ('<p>' + Student. name + '</p> ');

// Output Chen Hao
Document. write ('<p>' + Object. getPrototypeOf (Student). name + '</p> ');

Therefore, you can also call the function of the parent object in the sub-object function, just like the Base: func () in C ++. Therefore, we can use the code of the parent class by reloading the hello method, as shown below:

Copy codeThe Code is as follows: // The New SayHello method is reloaded.
Student. sayHello = function (person ){
Object. getPrototypeOf (this). sayHello. call (this );
Var hello = "my student no is:" + this. no + ", <br>" +
"My temporary ent is:" + this. dept;
Document. write (hello + '<br> ');
}

This is very powerful.

Combination
The above things cannot meet our requirements. We may want these objects to be truly combined. Why combination? Because we all know that this is the most important thing in OO design. However, this is not very well supported by Javascript, so we can still solve this problem.

First, we need to define a Composition function: (target is the object and source is the source object). The following code is very simple, is to take out the properties in source one by one and define them into target.

Copy codeThe Code is as follows: function Composition (target, source)
{
Var desc = Object. getOwnPropertyDescriptor;
Var prop = Object. getOwnPropertyNames;
Var def_prop = Object. defineProperty;

Prop (source). forEach (
Function (key ){
Def_prop (target, key, desc (source, key ))
}
)
Return target;
}

With this function, we can play here:

Copy codeThe Code is as follows: // artist
Var Artist = Object. create (null );
Artist. sing = function (){
Return this. name + 'starts singing ...';
}
Artist. paint = function (){
Return this. name + 'starts painting ...';
}

// Athletes
Var Sporter = Object. create (null );
Sporter. run = function (){
Return this. name + 'starts running ...';
}
Sporter. swim = function (){
Return this. name + 'starts memory Ming ...';
}

Composition (Person, Artist );
Document. write (Person. sing () + '<br> ');
Document. write (Person. paint () + '<br> ');

Composition (Person, Sporter );
Document. write (Person. run () + '<br> ');
Document. write (Person. swim () + '<br> ');

// Check what is in Person? (Output: sayHello, sing, paint, swim, run)
Document. write ('<p>' + Object. keys (Person) + '<br> ');

Prototype and inheritance
Let's talk about Prototype first. Let's take a look at the following routine. This routine does not need to be explained. It is similar to the function pointer in C language. It is much more common in C language.
Copy codeThe Code is as follows: var plus = function (x, y ){
Document. write (x + '+ y +' = '+ (x + y) +' <br> ');
Return x + y;
};

Var minus = function (x, y ){
Document. write (x + '-' + y + '=' + (x-y) + '<br> ');
Return x-y;
};

Var operations = {
'+': Plus,
'-': Minus
};

Var calculate = function (x, y, operation ){
Return operations [operation] (x, y );
};

Calculate (12, 4, '+ ');
Calculate (24, 3 ,'-');

So, can we encapsulate these things? We need to use prototype. See the following example:

Copy codeThe Code is as follows: var Cal = function (x, y ){
This. x = x;
This. y = y;
}

Cal. prototype. operations = {
'+': Function (x, y) {return x + y ;},
'-': Function (x, y) {return x-y ;}
};

Cal. prototype. calculate = function (operation ){
Return this. operations [operation] (this. x, this. y );
};

Var c = new Cal (4, 5 );

C. calculate ('+ ');
C. calculate ('-');

This is the usage of prototype. prototype is the most important content in javascript. There are too many articles on the Internet to introduce this thing. To put it bluntly, prototype is an extension of an object. It is characterized by "copying" an existing instance to return a new instance, rather than creating a new instance. The copied instance is what we call the prototype. This prototype can be customized (of course, there is no real copy here, but it is actually a delegate ). In the above example, we have extended the instance Cal so that it has an operations attribute and a calculate method.

In this way, we can implement inheritance through this feature. Remember the Person at the very beginning. The example below is to create a Student to inherit the Person.

Copy codeThe Code is as follows: function Person (name, email, website ){
This. name = name;
This. email = email;
This. website = website;
};

Person. prototype. sayHello = function (){
Var hello = "Hello, I am" + this. name + ", <br>" +
"My email is:" + this. email + ", <br>" +
"My website is:" + this. website;
Return hello;
};

Function Student (name, email, website, no, dept ){
Var proto = Object. getPrototypeOf;
Proto (Student. prototype). constructor. call (this, name, email, website );
This. no = no;
This. dept = dept;
}

// Inherit prototype
Student. prototype = Object. create (Person. prototype );

// Reset the constructor
Student. prototype. constructor = Student;

// Reload sayHello ()
Student. prototype. sayHello = function (){
Var proto = Object. getPrototypeOf;
Var hello = proto (Student. prototype). sayHello. call (this) + '<br> ';
Hello + = "my student no is:" + this. no + ", <br>" +
"My temporary ent is:" + this. dept;
Return hello;
};

Var me = new Student (
"Chen Hao ",
"Haoel@hotmail.com ",
"Http://jb51.net ",
"12345678 ",
"Computer Science"
);
Document. write (me. sayHello ());

Compatibility
The code above may not always run in all browsers, because the code above complies with the ECMAScript 5 specification and the browser compatibility list of ECMAScript 5, here you can see "ES5 browser compatibility table ".

All the code in this article has been tested in the latest version of Chrome.

The following are some functions that can be used in browsers that are incompatible with ES5:

Object. create () function
Copy codeThe Code is as follows: function clone (proto ){
Function Dummy (){}

Dummy. prototype = proto;
Dummy. prototype. constructor = Dummy;

Return new Dummy (); // equivalent to Object. create (Person );
}

Var me = clone (Person );

DefineProperty () function
Copy codeThe Code is as follows: function defineProperty (target, key, descriptor ){
If (descriptor. value ){
Target [key] = descriptor. value;
} Else {
Descriptor. get & target. _ defineGetter _ (key, descriptor. get );
Descriptor. set & target. _ defineSetter _ (key, descriptor. set );
}

Return target
}

Keys () function
Copy codeThe Code is as follows: function keys (object) {var result, key
Result = [];
For (key in object ){
If (object. hasOwnProperty (key) result. push (key)
}

Return result;
}

Object. getPrototypeOf () function
Copy codeThe Code is as follows: function proto (object ){
Return! Object? Null
: '_ Proto _' in object? Object. _ proto __
:/* Not exposed? */Object. constructor. prototype
}

Bind Functions
Copy codeThe Code is as follows: var slice = []. slice

Function bind (fn, bound_this) {var bound_args
Bound_args = slice. call (arguments, 2)
Return function () {var args
Args = bound_args.concat (slice. call (arguments ))
Return fn. apply (bound_this, args )}
}

Reference
W3CSchool
MDN (Mozilla Developer Network)
MSDN (Microsoft Software Development Network)
Understanding Javascript OOP.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.