This chapter is a summary of personal study notes from the book advanced Programming in JavaScript.

Best practices

I. Maintainability

□ Easy to understand: Without resorting to the original developer, anyone can look at the code and know what it does and how it is implemented. □ Common sense: Everything in the code makes sense, no matter how complicated the operation. □ Easy to adapt: even if the data changes, there is no need to completely rewrite. ■ Easy to extend: The code architecture is carefully designed to support future extensions of core functionality. □ Easy to debug: When a problem occurs, the code can give clear information that can directly locate the problem.

-> Proper naming of variables and functions in your code is essential for readability and maintainability, as well as for developer professionalism! <-

1. Names of variables and functions:

1.1). Variable names should be nouns, such as person and form. Function names should start with a verb, such as getName(). Functions that return a Boolean value usually start with is, such as isEnabled (). Functions and methods should start with lowercase letters and use addHandler. Class names should start with uppercase letters, such as class Person. Constant values should be all uppercase and followed by an underscore, such as REQUEST_TIMEOUT. 1.4). Try to use descriptive and intuitive words, but do not be too long. GetName () returns the name, and PersonFactory () returns the creation of a Person object or entity.

2. Variable type transparency

2.1). The first way to specify the type of a variable is through initialization. When you define a variable, you should immediately initialize it to a value of the type to be used in the future, for example:

let found=false; // Let count=-1; Let name=""; // Let person=null; / / objectCopy the code

2.2). The second way to specify the type of a variable is to use Hungarian notation, which prefixes the variable name with one or more characters to indicate the data type, usually o for object, s for string, I for integer, f for float, and b for Boolean. Such as:

let bfound ; // Let icount; // let sname; // String let operson; / / objectCopy the code

2.3). A third way to indicate the type of a variable is to use type annotations. The type annotation is placed after the variable name and before the initialization expression:

Let the found / * : Boolean * / = false; Let the count / * : int * / = 1; let name/*String*/=""; let person/*Object*/=null;Copy the code

The disadvantage of type annotations is that they cannot be commented out using a large block of code.

3. Loose coupling

When one part of the application depends too closely on another part, the code becomes tightly coupled and therefore difficult to maintain. A typical problem is to reference one object directly to another, so modifying one may necessitate modifying the other.

<! <script> document.write("hello,boy!") ); </script> <! <input type="button" value="Clik me"onclick="doSomething()">Copy the code

3.1). Decouple HTML/Javascript: Try not to embed or include Javascript directly in HTML, ideally HTML and Javascript should be completely separate, with Javascript imported through external files. When HTML and Javascript are tightly coupled, each error in Javascript should be analyzed to determine whether the error came from HTML or Javascript. This also introduces new errors in code availability.

Another way to do this is to include HTML in JavaScript. This usually happens when you insert a piece of HTML into the page via innerHTML. In general, try to avoid creating a lot of HTML in JavaScript.

function insertMessage(mas) {
  let container = document.getElementById("container");
  container.innerHTML = `<div class="mas">
    <p>class="post">${msg}</p>
    <p><em>Latest message above.</em></p>
    </div>`;
}
Copy the code

Decoupling HTML and JavaScript can save time because it is easier to locate the source of the error. Decoupling also helps to ensure maintainability. The modification behavior refers only to JavaScript, and the modification tag refers only to the file to be rendered.

3.2). Decouple CSS/JavaScript: Tight coupling can also occur between CSS and JavaScript. The most common example is using JavaScript to modify individual styles:

     element.style.color = "red";
     element.style.backgroundColor = "bule"
     
Copy the code

Since CSS is responsible for displaying the page, any styling issues should be addressed through the CSS file, but modifying individual styles directly using JavaScript adds a factor to consider and even to modify when typographical. What follows could be a nightmare! Modern Web applications often use JavaScript to change styles, so while it is not possible to completely decouple CSS from JavaScript, it is possible to make it loose, mainly by dynamically changing ‘class names’ rather than styles:

    element.className="edit";
Copy the code

By changing the CSS class name of the element, you can limit most styles to the CSS file. JavaScript is only responsible for changing the class name of the application style, but does not directly affect the style of the element. If the class name of the application is correct, then the problem with the display is CSS, not JavaScript. Behavior problems should only be found in JavaScript to improve the maintainability of the entire application.

3.3). Decouple application logic/event handlers:

  function handleKeyPress(event){
     if(event.keyCode==13){
       let target=event.target;
       let value=5*parseInt(target.value);
       if(value>10){
         document.getElementById("error-msg").style.display="block"
       }
     }
   }
 
Copy the code

In addition to handling events, this event handler contains application logic, resulting in a twofold situation. First, there is no way to trigger application logic other than the event, resulting in debugging difficulties. What if it doesn’t produce the desired results? Is there no debugging event handler, or is the application logic faulty? Second, if subsequent events also correspond to the same application logic, it can lead to code duplication or extracting it into separate functions. Leads to unnecessary work. A better approach is to separate the application logic from the event handlers, each doing its own thing.

function validateValue(value) { value = 5 * parseInt(value); if (value > 10) { document.getElementById("error-msg").style.display = "block"; } } function handleKeyPress(event) { if (event.keyCode == 13) { let target = event.target; validateValue(target.value); }}Copy the code

With this change, the application logic is separated from the event handlers. The handleKeyPress(Event) function checks to see if the user pressed the enter key. If so, it gets the event target and passes the target value to the validateValue(Value) function. Separating application logic from event handlers has many benefits. First, it allows you to easily modify the events that are triggered with minimal effort. If the original mouse click trigger process, phenomenon and want to add keyboard operation trigger, modify it is also convenient and simple. Second, you can test your code without adding events, making it easy to create unit tests or automate your application process.

Here are some things to be aware of when decoupling application logic from business logic:

* Don't pass the Event object to other methods, just pass the necessary data from the Event object. ** Every possible operation in the application should be performed without the order of the event handler. *** Event handlers should handle events, leaving subsequent processing to the application logic.Copy the code
4. Coding conventions

4.1). Do not declare global variables

Try not to declare global variables and functions as much as possible in order to create a consistent and maintainable environment for running scripts. You can create up to one global variable to serve as a namespace for other objects and functions. Such as:

var name="Nicholas"; Function sayName(){console.log(name); } var MyApplication={// a variable name:"Nicholas", sayName:function(){console.log(this.name); }Copy the code

The overwritten version declares only one global object, MyApplication. This object contains a name and sayName(), which avoids the problems of the previous version. First, the name variable overrides the window.name attribute, which can affect other functionality. Second, it helps to distinguish where the functionality is concentrated. Calling MyApplication () implies that any problem can be found in its own code.

Global objects can be extended to the concept of namespaces, which involve creating an object through which capabilities are exposed. An object is a container in which all other objects are contained, and as long as you use an object to organize functionality in this way, you can call it a namespace.

var work={}; work.ProJS={}; work.ProJS.EventUtil={... }; work.ProJS.CookieYtil={... }; /* Renaming only occurs in different namespaces */ work.ProAjax={}; work.ProAjax.EventUtil={... }; work.ProAjax.CookieYtil={... };Copy the code

4.2). Do not compare null

In reality, simply comparing null is often not enough; checking the type of a value really checks the type, not what it can’t be. If you see a null comparison code, you should replace it with one of the following techniques:

If you want the value to be an object with a particular method name, you use the Typeof operator to ensure that the method with the given name exists on the object.Copy the code

4.3). Using constants:

– Recurring values: Any value that is used more than once should be extracted into a constant. This will eliminate errors that occur when one value is changed and the other is not. – User interface strings: Any strings that will be displayed to the user should be extracted to facilitate internationalization. -URL: The addresses of resources in a Web application change frequently, so it is recommended that all urls be managed in one place. – Any variable values: When using a literal in your code, ask yourself if the value will change in the future, and if so, extract it into a constant.


Performance of two.

-1. Scope awareness

Accessing a global variable scope is always slower than accessing a local variable because the scope must be traversed, and anything that reduces the time it takes to traverse the scope can improve performance code.

function updateUI(){ let imgs=document.getElementsByTagName("img"); for(let i=0,len=imgs.length; i<len; i++){ imgs[i].title='${document.title} image ${i}'; } let msg=document.getElementById("msg"); msg.innerHTML="Update complete."; }Copy the code

This function looks fine, but it references the global Document object in three places, and if you have a lot of images on the page, then the for loop references the document dozens of times or more, each time you iterate through the scope chain, and by saving a reference to the Document object in the local scope, Can significantly improve the performance of this function because only the scope chain lookup is required. With a local variable pointing to the document object, we can improve the performance of this function by limiting the number of global lookups to one:

function updateUI(){ let doc=document; let imgs=doc.getElementsByTagName("img"); for(let i=0,len=imgs.length; i<len; i++){ imgs[i].title='${doc.title} image ${i}'; } let msg=doc.getElementById("msg"); msg.innerHTML="Update complete."; }Copy the code

This call only looks up the scope chain once. As a rule of thumb, whenever a global object is referenced more than twice in a function, it should be saved as a local variable.

-2. Avoid using the with statement in performance. Like a function, the with statement creates its own scope, thus lengthening the scope chain of the code within it.

-3. Minimize statements

A single statement that can perform multiple operations is faster than one operation per statement in multiple statements.

① Multiple declaration variables:

let count=5; let color="blue"; Let value = [1, 2, 3]; let now=new Date();Copy the code

Using a single let to declare all variables, separated by commas, is faster than executing multiple statements:

Let count=5, color="blue", value=[1,2,3], now=new Date();Copy the code

(2) Insert iterative values:

let name=value[i]; i++; Try to insert iterative values into a statement using: let name=value[i++];Copy the code

③ Using arrays and object literals:

Let values=new Array(); values[0]=132; values[1]=456; values[2]=789; Let Person=new Object(); let Person=new Object(); Person.name="zhangmazi"; Person.age=37; Person.sayName=function(){ console.log(this.name)Copy the code

(4) Convert to literal form:

Let values=[123,456,789]; Let person={name:"zhangmazi", age:37, sayName(){console.log(this.name); }}Copy the code

-4. Optimize DOM interaction

Minimize real-time updates – When accessing the DOM, as long as the part accessed is part of the displayed page, you are performing real-time updates. Here’s an example:

let list = document.getElementById("mylist"),
  item;
for (let i = 0; i < 10; i++) {
  item = document.createElement("li");
  list.appendChild(item);
  item.appendChild(document.createTextNode('Item ${i}'));
}
Copy the code

The above code adds 10 items to the list, each one updated in real time twice, once adding the Li element, once adding a text node to it, and finally 20 times. To solve the performance problem here, you need to reduce the number of real-time updates.

Build the DOM structure with the document fragment and add it to the list element once and for all. You can reduce real-time updates and avoid page flickering:

let list = document.getElementById("mylist"),
  fragment = document.createDocumentFragment(),
  item;
for (let i = 0; i < 10; i++) {
  item = document.createElement("li");
  fragment.appendChild(item);
  item.appendChild(document.createTextNode("Item" + i));
}
list.appendChild(fragment);
Copy the code

– 5. Use innerHTML

There are two ways to create new DOM nodes in a page: using DOM methods such as createElement() and appendChild(), and using innerHTML. For a small number of DOM updates there is little difference, but for a large number of DOM updates, using innerHTML is much faster.

let list=document.getElementById("mylist"), html=""; for(let i=0; i<10; i++){ html+='<li>Item ${i}</li>'; } list.innerHTML=html;Copy the code

The code above constructs an HTML string and then assigns it to list.innerHTML. The result also creates the appropriate DOM destruct. Although concatenating strings has some performance costs, this technique is still faster than performing multiple DOM operations.

-6. Use event delegate

Most Web applications make heavy use of event handlers for user interaction. The number of event handlers in a page is directly related to how quickly the page responds to user interaction. To minimize the impact on page responses, event delegates should be used whenever possible. The event delegate takes advantage of the bubble. With the knowledge that any bubbling event can be not on the event target, but on any ancestor element of the target, event handlers can be added to high-level elements responsible for processing multiple targets. Event handlers should be added to the document whenever possible, because entire page events can be handled at the document level.

7. Note HTMLCoollection

Any time an HTMLCollection is accessed, whether its properties or methods, it triggers a query of the document, which is quite time-consuming, and reducing access to it can greatly improve script performance! When you write JavaScript code that returns an HTMLCollection object, try not to access it. HTMLCollection is returned in the following cases:

* call getElementsByTagName (); ** Read element childNodes attribute; *** Read the attributes attribute of the element; **** access special collections such as document.form, document.images, etc.Copy the code

File structure

The build process begins by defining the logical structure for storing files in source control. It’s best not to include all your JavaScript code in one file. Instead, follow the typical pattern of object-oriented programming languages and keep the objects and custom types in their own separate files. This allows each file to contain a minimum amount of code, making later modifications easier and less prone to introducing errors. In addition, in environments where concurrent source control systems such as Git, CVS, or Subversion are used, this reduces the risk of merging conflicts. Note that spreading the code across multiple files is a maintainability, not a deployment, point of view. For deployment, you should combine all source files into one or more summary files. The fewer JavaScript files your Web application uses, the better, because HTTP requests are a major performance bottleneck for some Web applications. And, using

Module packer

Writing code as a module doesn’t mean you have to deliver code as a module. Often JavaScript code consisting of a large number of modules needs to be packaged together at build time and delivered as one or a few JavaScript files. The module packager’s job is to identify the JaveaSeript dependencies involved in the application, combine them into one large file, complete the serial organization and splicing of the modules, and then generate the output file that is ultimately provided to the browser. There are many tools that enable module packaging. Webpack, Rollupt, and Browserify are just a few that can turn module-based code into universally compatible web scripts.

The revolutionary will must be firm!