Home  >  Article  >  Web Front-end  >  How to write maintainable object-oriented JavaScript code

How to write maintainable object-oriented JavaScript code

高洛峰
高洛峰Original
2016-11-26 10:15:32799browse

Being able to write maintainable object-oriented JavaScript code not only saves money, but also makes you popular. Do not believe? It's possible that you or someone else will come back and reuse your code one day. If you can make this experience as less painful as possible, you can save a lot of time. Everyone on earth knows that time is money. Likewise, you may earn someone's favor by saving them a headache. But before we start exploring how to write maintainable object-oriented JavaScript code, let’s take a quick look at what object-oriented is. If you already understand object-oriented concepts, you can skip the next section directly.
What is object-oriented?
Object-oriented programming mainly represents physical objects in the real world through code. To create an object, you first need to write a "class" to define it. Classes can represent almost anything: accounts, employees, navigation menus, cars, plants, ads, drinks, etc. And every time you want to create an object, instantiate an object from the class. In other words, an instance of a class is created as an object. In fact, objects are usually used when dealing with more than one thing of the same type. Plus, just simple functional programs can do a great job. Objects are essentially containers for data. Therefore, in an employee object, you may want to store the employee number, name, date of joining, title, salary, seniority, etc. Objects also contain functions (also called "methods") that process data. Methods are used as intermediaries to ensure data integrity and to transform data before storage. For example, a method could accept a date in any format and convert it into a standardized format before storing it. Finally, classes can also inherit from other classes. Inheritance allows you to reuse the same code in different classes. For example, both bank accounts and video store accounts can inherit a basic account class, which includes personal information, account opening date, branch information, etc. Then each can define its own data structures and methods for transaction or loan processing.
Warning: JavaScript object-oriented is not the same
In the previous section, the basics of classic object-oriented programming were outlined. I say classic because JavaScript doesn't follow these rules. In contrast, JavaScript classes are written as functions, and inheritance is implemented through prototypes. Prototypal inheritance basically means using prototype properties to implement inheritance of objects instead of inheriting classes from classes.
Instantiation of objects
The following is an example of object instantiation in JavaScript:
// Define Employee class
 function Employee(num, fname, lname) {
  this.getFullName = function () {
  return fname + " " + lname ;
   }
  };
 
  // Instantiate the Employee object
 var john = new Employee("4815162342", "John", "Doe");
  alert("The employee's full name is " + john.getFullName() );
Here, there are three important points to note:
1 The first letter of the "class" function name must be capitalized. This indicates that the function is intended to be instantiated rather than called like a normal function.
2 The new operator is used during instantiation. If you omit new and just call the function, many problems will occur.
3 Because getFullName is assigned to this operator, it is publicly available, but fname and lname are not. The closure generated by the Employee function gives getFullName access to fname and lname, but remains private to other classes.
Prototypal inheritance
The following is an example of prototypal inheritance in JavaScript:
// Define the Human class
function Human() {
this.setName = function (fname, lname) {
this.fname = fname;
this.lname = lname ;}} I This.getfulname = Function () {
Return this.fname + " + this.lname; This.getnum = Fundction ( ) {
            return num;
     }
};
//Let Employee inherit the Human class
Employee.prototype = new Human();
           // Instantiate the Employee object
var john = new Employee("4815162342");
john.setName("John", "Doe");
alert(john.getFullName() + "'s employee number is " + john.getNum());
This time, the created Human class contains everything common to humans Properties - I also put fname and lname in because it's not just employees who have names, everyone has names. Then assign the Human object to its prototype property.
Code reuse through inheritance
In the previous example, the original Employee class was broken into two parts. All common human attributes were moved to the Human class, and then Employee inherited Human. In this case, the properties in Human can be used by other objects, such as Student, Client, Citizen, Visitor, etc. Now you may have noticed that this is a great way to split and reuse code. When dealing with Human objects, you only need to inherit Human to use the existing properties, instead of re-creating each different object one by one. In addition, if you want to add a "middle name" attribute, you only need to add it once, and those that inherit the Human class can use it immediately. On the contrary, if we just want to add the "middle name" attribute to an object, we can add it directly to that object without adding it to the Human class.
1. Public and Private
For the next topic, I want to talk about public and private variables in classes. Depending on how the data is handled in the object, the data will be treated as private or public. Private properties do not necessarily mean that others cannot access them. Maybe only a certain method needs to be used.
● Read only
Sometimes, you just want a value when creating an object. Once created, you don't want others to change this value. To do this, create a private variable and assign a value to it during instantiation.
function Animal(type) {
var data = [];
data['type'] = type;
this.getType = function () {
return data['type'];
}
}

var fluffy = new Animal('dog');
fluffy.getType(); // Return 'dog'
In this example, a local array data is created in the Animal class. When the Animal object is instantiated, a value of type is passed and that value is placed in the data array. Because it is private, the value cannot be overwritten (the Animal function defines its scope). Once the object is instantiated, the only way to read the type value is to call the getType method. Because getType is defined in Animal, getType can enter data with the closure generated by Animal. In this case, although the type of the object can be read, it cannot be changed.
One very important point is that when the object is inherited, the "read-only" technology cannot be used. After inheritance is performed, each instantiated object shares those read-only variables and overwrites their values. The simplest solution is to convert the read-only variables in the class into public variables. But you have to keep them private, you can use the technique Philippe mentioned in the comments.
● Public
Of course, there are times when you want to read and write the value of a certain attribute at will. To achieve this, use the this operator.
function Animal() {
this.mood = '';
}

var fluffy = new Animal();
fluffy.mood = 'happy';
fluffy.mood; // Return 'happy'
This time Animal The class exposes a property called mood, which can be read and written at will. Likewise, you can assign functions to public properties, such as the getType function in the previous example. Just be careful not to assign a value to getType or you will destroy it.
Completely Private
Finally, you may find that you need a fully private local variable. This way, you can use the same pattern as in the first example without creating public methods.
function Animal() {
var secret = "You'll never know!"
}

var fluffy = new Animal();
2. Write a flexible API
Now that we have talked about class creation, in order to keep things consistent with Product requirements change synchronously, and we need to keep the code from becoming outdated. If you have already done some projects or maintained a product for a long time, then you should know that the requirements change. This is an indisputable fact. If you don't think so, your code will be doomed before it's even written. Maybe you suddenly need to animate the contents of a tab, or get data through an Ajax call. Although it is impossible to accurately predict the future, it is possible to write flexible code to prepare for future emergencies.
● Saner parameter list
When designing the parameter list, you can make the code forward-looking. The parameter list is the main point of contact for others to implement your code, and it can be very problematic if it is not designed well. You should avoid parameter lists like this:
function Person(employeeId, fname, lname, tel, fax, email, email2, dob) {
};
This class is very fragile. If you want to add a middle name parameter after you publish the code, you will have to add it at the end of the list because of ordering issues. This makes work awkward. It would be very difficult if you didn't assign a value to each parameter. For example:
var ara = new Person(1234, "Ara", "Pehlivanian", "514-555-1234", null, null, null, "1976-05-17");
A neater and more flexible way to manipulate parameter lists is to use this pattern:
function Person(employeeId, data) {
};
There is the first parameter because it is required. The rest is mixed into the object so that it can be used flexibly.
var ara = new Person(1234, {
 fname: "Ara",
 lname: "Pehlivanian",
 tel: "514-555-1234",
 dob: "1976-05-17"
});
The beauty of this pattern is that it's both easy to read and highly flexible. Notice that fax, email and email2 are completely ignored. Not only that, the objects are in no particular order, so it's very easy to add a middle name parameter wherever convenient:
var ara = new Person(1234, {
 fname: "Ara",
 mname: "Chris",
lname: "Pehlivanian",
tel: "514-555-1234",
dob: "1976-05-17"
}); The code inside the
class is not important because the values ​​inside can be accessed through the index:
function Person(employeeId, data) {
this.fname = data['fname'];
};
If data['fname'] returns a value, then it is set. Otherwise, if it is not set properly, there is no loss.
● Make code embeddable
Over time, product requirements may require more behavior from your classes. But this behavior has nothing to do with the core functionality of your class. It may also be the only implementation of the class, such as graying out the content in the panel of one tab when it obtains external data from another tab. You might want to put these functions inside the class, but they don't belong there. The responsibility of the tab strip lies in managing the tabs. Animating and getting data are two completely different things and must be separated from the tab strip's code. The only way to future-proof your tab strip without excluding extra functionality is to allow behavior to be embedded in the code. In other words, create events and have them hooked into key moments in your code, such as onTabChange, afterTabChange, onShowPanel, afterShowPanel, etc. That way, they can easily hook into your onShowPanel event, write a handler that grays out the panel's content, and everyone is happy. JavaScript libraries make it easy enough for you to do this, but it's not that hard to write yourself. Below is an example using YUI 3.

< script type="text/javascript">
YUI().use('event', function (Y) {

function TabStrip() {
this.showPanel = function () {
This.fire('onShowPanel' );  Give TabStrip the ability to trigger common events
          Y.augment(TabStrip, Y.EventTarget);

         var ts = new TabStrip();
                                                                                                                                                                                               } ); S Ts.on ('Onshowpanel', Function () {
// Other things to do before displaying the panel}}); What to do next
                   );This example has a simple TabStrip class with a showPanel method. This method fires two events, onShowPanel and afterShowPanel. This capability is achieved by extending the class with Y.EventTarget. Once that's done, we instantiate a TabStrip object and assign a bunch of handlers to it. This is common code to handle the only behavior of an instance without cluttering the current class.
Summary
If you plan to reuse code, whether on the same page, within the same website, or across projects, consider packaging and organizing it inside classes. Object-oriented JavaScript naturally facilitates better code organization and code reuse. Beyond that, with a little foresight you can make sure your code is flexible enough to last long after you've written it. Writing reusable, future-proof JavaScript code saves you, your team, and your company time and money. This will definitely make you a hit.

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