This article mainly describes how to write high-quality JS code and related materials. if you want to write an efficient javascript class library, you can refer to it;
I try to read other people's class libraries, but I can understand them;
I plan to study js advanced functions, but the content in authoritative books is too fragmented,
Even if you remember "usage", you do not want to "use" it ".
Maybe you are just like me. it seems that you have taken care of the invisible power to constrain our plan. This makes us think that the limitations of our knowledge have made us unable to move forward.
During this period, various assignments, course design, lab reports, and increased pressure. It is rare to squeeze out a little time, never sleep, and sort out and summarize the books read in the past, just to be a little closer to writing your own class libraries.
This article is based on the essence of javascript language and Dynamic JavaScript. The examples have been debugged. after understanding them, I want to make some "esoteric" truth a little more simple.
1. variable scope
Scope is like oxygen for programmers. It is everywhere, and you may not think about it. But when it is contaminated (such as using a global object), you will feel suffocated (such as slow application response ). The javascript core scope rules are simple, well-designed, and powerful. To effectively use javascript, you need to master some basic concepts of variable scopes and understand the extreme situations that may cause unpredictable and annoying problems.
1.1 use as few global variables as possible
Javascript can easily create variables in the global namespace. Creating a global variable is effortless because it does not require any form of declaration and can be automatically accessed by all the code of the entire program.
For beginners, we may encounter certain requirements (for example, when the transmitted data is recorded, used when a function is called at a certain time, or when a function is frequently used, without hesitation, I thought about global functions. even the process-oriented C language I learned in my freshman year was too deep-rooted, and the system was full of functions. Defining global variables will pollute shared public namespaces and may lead to unexpected naming conflicts. Global variables are not conducive to modularization, because they lead to unnecessary coupling between independent components in the program. Seriously, too many global features (including style sheets, directly defining p or a Styles) and integrating them into multi-person development titles will become catastrophic errors. This is why all jQuery code is wrapped in an anonymous expression that is executed immediately-self-called anonymous function. After the browser loads the jQuery file, it starts to execute the function immediately after calling the anonymous function and initializes each module of jQuery to avoid damaging and polluting global variables and affecting other code.
The code is as follows:
(Function (window, undefined ){
Var jQuery =...
//...
Window. jQuery = window. $ = jQuery;
}) (Window );
In addition, you may think that "how to write first and then sort it out later" is more convenient, however, excellent programmers constantly pay attention to the program structure, constantly classify related functions, and separate irrelevant components, and these behaviors are part of the programming terminology.
Because the global namespace is the only way to interact with independent components in javascript programs, it is inevitable to use global naming controls. Components or libraries have to define some global variables. So that other parts of the program can be used. Otherwise, it is best to use local variables.
The code is as follows:
This. foo; // undefined
Foo = "global foo ";
This. foo; // "global foo"
Var foo = "global foo ";
This. foo = "changed ";
Foo; // changed
The global namespace of javascript is also exposed to global objects that can be accessed in the global scope of the program. this object serves as the initial value of this keyword. In a web browser, global objects are bound to the global window variable. This means that there are two ways to create a global variable: declare it with var in the global scope, or add it to the global object. The advantage of using var declaration is that it can clearly express the impact of global variables in the program scope.
Given that reference to bound global variables can cause runtime errors, clear and concise saving scopes make it easier for code users to understand the global variables declared by the program.
Because the global object provides a dynamic response mechanism for the global environment, you can use it to query a runtime environment and detect which features are available on this platform.
Eg. ES5 introduces a global JSON object to read and write data in JSON format.
The code is as follows:
If (! This. JSON ){
This. JSON = {
Parse :..,
Stringify :...
}
}
If you provide JSON implementation, you can use your own implementation simply and unconditionally. However, the built-in implementations provided by the host environment are almost more suitable because they are written into the browser in C language. Because they strictly check the correctness and consistency according to certain standards, and generally provide better performance than third-party implementations.
At the beginning, the data structure course was designed to simulate the basic operations of strings, and the methods provided by the language itself were not required. Javascript implements the basic operations on arrays very well. if it is just for the general learning needs, the idea of the methods provided by the simulation language itself is very good, but if it is really put into development, you do not need to consider using the javascript built-in method as soon as possible.
1.2 avoid using
With statements provide any "convenience" to make your applications unreliable and inefficient. We need to call a series of methods for a single object in sequence. Using the with statement can easily avoid repeated references to objects:
The code is as follows:
Function status (info ){
Var widget = new Widget ();
With (widget ){
SetBackground ("blue ");
SetForeground ("white ");
SetText ("Status:" + info );
Show ();
}
}
It is also tempting to use the with statement to "import" (import) variables from the module object.
The code is as follows:
Function f (x, y ){
With (Math ){
Return min (round (x), sqrt (y); // abstract reference
}
}
In fact, javascript treats all variables the same. Javascript looks for variables from the inmost scope. The with language treats an object as if it represents a variable scope. Therefore, within the with code block, the variable search starts from searching for the attributes of a given variable name. If this attribute is not found in this object, the search will continue in the external scope. Each reference to an external variable in the with block is implicitly assumed that the with object (and any of its prototype objects) does not have an attribute of the same name. Creating or modifying a with object or its prototype object elsewhere in the program does not necessarily follow this assumption. The javascript engine certainly does not read local code to obtain the local variables you use. Javascript scopes can be expressed as efficient internal data structures, and variable search can be very fast. However, because the with code block needs to search for the prototype chain of the object to find all the variables in the with code, its running speed is far lower than the normal code block.
Instead of the with language, an easy way is to bind an object to a short variable name.
The code is as follows:
Function status (info ){
Var w = new Widget ();
W. setBackground ("blue ");
W. setForeground ("white ");
W. setText ("Status:" + info );
W. show ();
}
In other cases, the best way is to explicitly bind local variables to relevant attributes.
The code is as follows:
Function f (x, y ){
Var min = Math. min,
Round = Math. round,
Sqrt = Math. sqrt;
Return min (round (x), sqrt (y ));
}
1.3 familiar with closures
There is a single concept for understanding closures:
A) javascript allows you to reference variables defined outside the current function.
The code is as follows:
Function makeSandwich (){
Var magicIngredient = "peanut butter ";
Function make (filling ){
Return magicIngredient + "and" + filling;
}
Return make ("jelly ");
}
MakeSandwich (); // "peanut butter and jelly"
B) even if the external function has returned, the current function can still reference the variables defined in the external function.
The code is as follows:
Function makeSandwich (){
Var magicIngredient = "peanut butter ";
Function make (filling ){
Return magicIngredient + "and" + filling;
}
Return make;
}
Var f = sandwichMaker ();
F ("jelly"); // "peanut butter and jelly"
F ("bananas"); // "peanut butter and bananas"
F ("mallows"); // "peanut butter and mallows"
The function value of javascriptd contains more information than the code required to call them. In addition, javascript function values are also stored internally and they may reference variables defined in their closed scopes. The functions that track variables within the scope they cover are called closures.
The make function is a closure. its code references two external variables: magicIngredient and filling. Every time the make function is called, its code can reference these two variables, because the closure stores these two variables.
A function can reference any variable in its scope, including parameters and external function variables. We can use this to compile more general sandwichMaker functions.
The code is as follows:
Function makeSandwich (magicIngredient ){
Function make (filling ){
Return magicIngredient + "and" + filling;
}
Return make;
}
Var f = sandwichMaker ("ham");
F ("cheese"); // "ham and cheese"
F ("mustard"); // "ham and mustard"
Closure is one of the most elegant and expressive features of javascript and is also the core of many usage habits.
C) the closure can update the value of an external variable.In fact, closures store references to external variables rather than copies of their values. Therefore, any closure that has access to these external variables can be updated.
The code is as follows:
Function box (){
Var val = undefined;
Return {
Set: function (newval) {val = newval ;},
Get: function () {return val ;},
Type: function () {return typeof val ;}
};
}
Var B = box ();
B. type (); // undefined
B. set (98.6 );
B. get (); // 98.6
B. type (); // number
This example generates an object that contains three closures. The three closures are set, type, and get Attributes. they all share the access val variable, and the set closure updates the val value. Call get and type to view the update result.
1.4 improve understanding of variable declaration
Javascript supports this method of scope (reference to the variable foo will be bound to the latest scope for declaring the foo variable ), however, block-level scopes are not supported (the scope defined by a variable is not a closed statement or code block closest to it ).
Failing to understand this feature will cause some subtle bugs:
The code is as follows:
Function isWinner (player, others ){
Var highest = 0;
For (var I = 0, n = others. length; I Var player = others [I];
If (player. score> highest ){
Highest = player. score;
}
}
Return player. score> highest;
}
1.5 Beware of the clumsy scope of the naming function expression
The code is as follows:
Function double (x) {return x * 2 ;}
Var f = function (x) {return x * 2 ;}
The same function code can also be used as an expression, but it has different meanings. The official difference between an anonymous function and a named function expression is that the latter is bound to a variable with the same name as the function, and the variable is used as a local variable of the function. This can be used to write recursive function expressions.
The code is as follows:
Var f = function find (tree, key ){
//....
Return find (tree. left, key) |
Find (tree. right, key );
}
It is worth noting that the scope of the variable find is only in its own functions. Unlike the function declaration, the name function expression cannot be referenced externally through its internal function name.
The code is as follows:
Find (myTree, "foo"); // error: find is not defined;
Var constructor = function () {return null ;}
Var f = function (){
Return constructor ();
};
F (); // {} (in ES3 environments)
This program seems to generate null, but will actually generate a new object.
Because the scope of the namefunction variable inherits the Object. prototype. constructor (Oject constructor). like with statements, this scope will be caused by Object. the dynamic changes of prototype are affected. In the system, the function expression scope to avoid Object contamination is to avoid adding properties to the Object. prototype at any time to avoid using any local variables with the same name as the standard Object. prototype attribute.
Another drawback of the popular javascript engine is to improve the declaration of the naming function expression.
The code is as follows:
Var f = function g () {return 17 ;}
G (); // 17 (in nonconformat environment)
Some javascript environments even use the f and g functions as different objects, resulting in unnecessary memory allocation.
1.6 beware of the clumsy scope of partial block function declaration
The code is as follows:
Function f () {return "global ";}
Function test (x ){
Function f () {return "local ";}
Var result = [];
If (x ){
Result. push (f ());
}
Result. push (f ());
Result;
}
Test (true); // ["local", "local"]
Test (false); // ["local"]
The code is as follows:
Function f () {return "global ";}
Function test (x ){
Var result = [];
If (x ){
Function f () {return "local ";}
Result. push (f ());
}
Result. push (f ());
Result;
}
Test (true); // ["local", "local"]
Test (false); // ["local"]
Javascript has no block-level scope, so the scope of internal function f should be the entire test function. Some javascript environments do, but not all javascript environments do, javascript implementation reports such functions as errors in strict mode (programs in strict mode with partial block function declarations report a syntax error), which helps to detect non-portable code, for future standard versions, partial block functions are declared to be more intelligent and semantic. In this case, you can consider declaring a local variable pointing to the global function f in the test function.