Home >Web Front-end >JS Tutorial >Javascript object-oriented programming (coolshell)_js object-oriented

Javascript object-oriented programming (coolshell)_js object-oriented

WBOY
WBOYOriginal
2016-05-16 17:55:081293browse

In the past two days, a former colleague has been asking me about object-oriented programming in Javascript, so I would like to write an article for him to read. This article mainly wants to explain object-oriented programming in Javascript from an overall perspective. (The writing is hasty and there may be inaccuracies or errors. Please criticize and correct me)
In addition, this article is mainly based on ECMAScript 5 and aims to introduce new technologies. Regarding compatibility, please see the last section.

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

Copy code Code As follows:

var name = 'Chen Hao';;
var email = 'haoel(@)hotmail.com';
var website = 'http://jb51.net ';

If you want to write it in objects, it will look like this:

Copy code The code is as follows:

var chenhao = {
name :'Chen Hao',
email : 'haoel(@)hotmail.com',
website : ' http://jb51.net'
};

So, I can access it like this:

Copy code The code is as follows:

//As a member
chenhao.name;
chenhao.email;
chenhao.website;

//In the form of hash map
chenhao["name"];
chenhao["email"];
chenhao["website"];

Regarding functions, we know that Javascript functions are like this:


Copy code The code is as follows:
var doSomething = function(){
alert('Hello World.');
};

So, we can do this:

Copy code The 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);
};

//Direct assignment, this is very similar to the C/C function pointer
chenhao.Hello = sayHello;

chenhao.Hello();

I believe these things are relatively simple , everyone understands. You can see that the JavaScript object function is directly declared, assigned directly, and used directly. Dynamic language for runtime.

There is also a more standardized way of writing:

Copy the code The code is as follows:

//We can see that it uses function as 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, to delete the properties of an object, it is very simple:

1 delete chenhao['email']

From the above examples, we can see the following points:

Javascript's data and member encapsulation is very simple. No class is entirely an object operation. Pure dynamics!
The this pointer in Javascript function is critical. If not, it is a local variable or local function.
Javascript object member functions can be temporarily declared when used, and a global function can be directly assigned to it.
Javascript member functions can be modified on the instance, which means that the behavior of the same function name in different instances may not be the same.
Property configuration – Object.defineProperty
First look at the following code:

Copy code The code is as follows:
//Create an object
var chenhao = Object.create(null);

//Set a property
Object.defineProperty( chenhao,
'name', { value: 'Chen Hao',
writable: true,
configurable: true,
enumerable: true });

//Set multiple properties
Object.defineProperties( chenhao,
{
'email' : { value: 'haoel@hotmail.com',
writable: true,
configurable: true,
enumerable: true },
'website': { value: 'http://jb51.net',
writable: true,
configurable: true,
enumerable: true }
}
);

Let’s talk about what these attribute configurations mean.

writable: Whether the value of this attribute can be changed.
configurable: Whether the configuration of this attribute can be changed.
enumerable: Whether this property can be traversed in a for...in loop or enumerated in Object.keys.
value: attribute value.
get()/set(_value): get and set accessors.
Get/Set accessor
Regarding the get/set accessor, it means using get/set to replace value (it cannot be used with value). The example is as follows:

Copy code The code is as follows:
var age = 0;
Object.defineProperty( chenhao,
'age', {
get: function() {return age 1;},
set: function(value) {age = value;}
enumerable : true,
configurable : true
}
);
chenhao.age = 100; //Call set
alert(chenhao.age); //Call get and output 101 (get hits 1);

We will Let’s look at a more practical example - use the existing attribute (age) to construct a new attribute (birth_year) through get and set:

Copy code The 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);

This seems a bit troublesome. Tell me, why don’t I write it like this? :

Copy code The 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 do this, but you can do these things through defineProperty():
1) Set attribute configurations such as writable, configurable, enumerable, etc.
2) Dynamically add attributes to an object. For example: some HTML DOM objects.

View object attribute configuration
If you view and manage these configurations of an object, there is a program below that can output the object's attributes and configuration:

Copy code The code is as follows:
//List the properties of the object.
function listProperties(obj)
{
var newLine = "
";
var names = Object.getOwnPropertyNames(obj);
for (var i = 0; i < names.length; i ) {
var prop = names[ i];
document.write(prop newLine);

// List the object’s property configuration (descriptor) using the getOwnPropertyDescriptor function.
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
Regarding the this pointer of Javascript, it is very similar to C/Java. Let’s take a look at an example: (This example is very simple, I won’t say more)

Copy code Code As follows:
function print(text){
document.write(this.value ' - ' text '
');
}

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 - a"
b.print('b'); // this => b, output "20 - b"

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

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

Copy the code The code is as follows:
print.call(a, 'a'); // this => a, output "10 - a"
print.call(b, 'b'); // this => b, output " 20 - b"

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

But after bind, the this pointer may be different, but because Javascript is dynamic. As in the following example

Copy code The code is as follows:
var p = print.bind(a );
p('a'); // this => a, output "10 - a"
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 see the following code. Student inherits from Object.

Copy code The 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 = "

Hello, I am " this.name ",
"
"my email is: " this.email ",
"
"my website is : " this.website;
document.write(hello "
");
}

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

//Use the attributes of Person
document.write(Student.name ' ' Student.email ' ' Student.website '
');

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

//Overload the SayHello method
Student. sayHello = function (person) {
var hello = "

Hello, I am " this.name ",
"
"my email is: " this.email ", "my website is: " this.website ",
"
"my student no is: " this. no ",
"
"my departent is: " this.dept;
document.write(hello '
');
}
//Call again
Student.sayHello();

//View Student Attributes (only no, dept and overloaded sayHello)
document.write('

' Object.keys(Student) '
');


Using the above example, we can see that the attributes in Person are not actually copied to Student, but we can access them. This is because Javascript implements this mechanism using delegates. In fact, this is the prototype, and Person is the prototype of Student.

When our code needs an attribute, the Javascript engine will first check whether the current object has this attribute. If not, it will check whether its Prototype object has this attribute, and it will continue. Continue until it finds or until there is no Prototype object.

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

Copy code The code is as follows:
Student.name = 'aaa';

//Output aaa
document.write('

' Student.name '
//Output Chen Hao
document.write('

' Object.getPrototypeOf(Student).name '

');

So, you can also call the function of the parent object in the function of the child object, just like Base::func() in C. Therefore, when we override the hello method, we can use the code of the parent class, as shown below:

Copy code The code is as follows:
//New version of the overloaded SayHello method
Student.sayHello = function (person) {
Object.getPrototypeOf(this).sayHello.call(this);
var hello = "my student no is: " this. no ",
"
"my departent is: " this. dept;
document.write(hello '
');
}

This is very powerful.

Composition
The above thing cannot meet our requirements, we may hope that these objects can be truly combined. Why combine? Because we all know that this is the most important thing in OO design. However, this does not support Javascript particularly well, so we can still get it done.

First of all, we need to define a Composition function: (target is the object that acts on it, and source is the source object). The following code is very simple. It just takes out the attributes in the source one by one and defines them to target.

Copy code The 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 You can play here:

Copy code The 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...';
}

//Sportsman
var Sporter = Object.create(null);
Sporter.run = function() {
return this.name ' starts running...';
}
Sporter.swim = function() {
return this.name ' starts swimming...';
}

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

Composition(Person, Sporter);
document.write(Person.run() '
');
document.write(Person.swim( ) '
');

//See what's in Person? (Output: sayHello,sing,paint,swim,run)
document.write('

' Object.keys(Person) '
');


Prototype and Inheritance
Let’s talk about Prototype first. Let's take a look at the following routine first. This routine does not need explanation. It is very similar to the function pointer in C language. There are many such things in C language.
Copy code The code is as follows:
var plus = function(x,y){
document. write( x ' ' y ' = ' (x y) '
');
return x y;
};

var minus = function(x,y){
document.write(x ' - ' y ' = ' (x-y) '
');
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 put these To encapsulate things, we need to use prototype. Look at the example below:

Copy the code The 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 the JavaScript language. There are too many articles on the Internet about this thing. To put it bluntly, prototype is to extend an object. Its characteristic is to return a new instance by "copying" an existing instance instead of creating a new instance. The copied instance is what we call a "prototype", and this prototype is customizable (of course, there is no real copy here, just delegation). In the above example, we extended the instance Cal to have an operations attribute and a calculate method.

In this way, we can implement inheritance through this feature. Remember our first Person, the following example is to create a Student to inherit Person.

Copy code The 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 ",
"
"my email is: " this.email ",
"
"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 constructor
Student.prototype.constructor = Student;

//Overload sayHello()
Student.prototype.sayHello = function(){
var proto = Object.getPrototypeOf;
var hello = proto(Student.prototype).sayHello.call(this) '
';
hello = "my student no is: " this. no ",
"
"my departent 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 above codes may not work in all browsers Run, because the above code follows the specifications of ECMAScript 5. For the browser compatibility list of ECMAScript 5, you can see the "ES5 browser compatibility list" here.

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

The following are some functions that can be used in browsers that are not ES5 compatible:

Object.create() function
Copy Code The 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 code The 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 code The 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 code The code is as follows:
function proto (object) {
return !object? null
: '__proto__' in object? object.__proto__
: /* not exposed? */ object.constructor.prototype
}

bind function
Copy code The 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) }
}

参考
W3CSchool
MDN (Mozilla Developer Network)
MSDN (Microsoft Software Development Network)
Understanding Javascript OOP.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn