Translated from: http://blog.jobbole.com/66135/
Today, both in the browser and outside the browser, the JavaScript world is undergoing tremendous changes. If we talk about script loading, the client's MVC framework, compressors, AMD, Common.js, and Coffeescript ... It just makes your brain faint. For those who are already familiar with these technologies, it may be hard to imagine that so far many JS developers are unfamiliar with these tools, and even in fact, they probably don't want to try them now.
This article will introduce some very basic JS knowledge, and need to know some things before developers want to try Backbone.js and ember.js tools. When you understand most of the content in this article, you will be more confident to learn other advanced JavaScript knowledge. This article assumes that you have used JavaScript before, so if you have never touched it, you may need to know more about the basics. Now let's get started!
Module
How many people write in a file JS like the code block below? (Note: I did not say embedded in the HTML file OH):
123 |
var somesharedvalue = ten; var myfunction = function () { //do something} var anotherimportantfunction = function () { / /do more Stuff} |
If you do this, chances are you're writing such a code. I'm not giving you a definition, because I've been writing this program for quite a long time. In fact, there are a lot of problems with this code, but we will focus on the pollution of the global namespace. This code will expose both the method and the variable to the global, we need to make this data independent of the global namespace, we will use the module pattern (modules pattern) to achieve this purpose. The module can have many different forms to reach our goal, I will start with the simplest method: the function expression called immediately (Immediately invoked function expressions, abbreviated as: Iife).
The name sounds very big, but its implementation is simple:
123 |
( function (){ //do some work })(); |
If you have never been in touch with this function before, you may now find it strange-how can there be so many parentheses! It is a function that executes immediately, and you can understand that a function is created and then called immediately. It should be an expression rather than a statement: A function statement must have a name, but as you can see, the immediate execution of the function is without a name. There is also a set of parentheses outside the function definition, which also helps us to easily find anonymous functions in our code.
Now that we know how to write an immediate execution function, let's talk about why you should use it. In JS we are all dealing with functions in various scopes, so if we want to create a scope, we can use the function. The scope of the variables and methods in the anonymous function is not polluting the global namespace just in the anonymous function, so the question to consider now is how do we get those variables and methods from outside in the scope of anonymous functions? The answer is the global namespace: Put the variable into the global namespace, or at least associate the action variable with the global namespace.
To invoke the method outside of the immediate execution function, we can pass the window object to the immediate execution function and assign the function or variable value to the object. To ensure that the introduction of the Window object does not cause any confusion, we can pass the widow object as a variable into our immediate execution function. The method of passing arguments as a function also applies to third-party libraries, even undefined such values. Now our immediate execution function looks like this:
123 |
( function (window, $, undefined){ //do some work })(window, jQuery); |
As you can see, we'll pass the window and jquery into the function (the ' $ ' notation means ' jQuery ', which is used to prevent other libraries from defining ' $ '), but this function actually receives 3 parameters. If we do not pass in the third argument, the value of the parameter undefined will remain in that state, and it will not change because the other code changes the global undefined. In fact, we can also use these values directly within the function, so the principle is that JS closures will overwrite the context in which they are located. For this topic, I have written an article on C # to explain the concept, which is interoperable.
Now we have a method that will execute immediately, as well as a relatively safe execution context, which also contains window,$ , and undefined Variables (These variables are still possible to be re-assigned before the script is executed, but the probability is much smaller now). Now we've done a good job of saving our code from a chaotic situation in the global context, reducing the likelihood of conflict with other scripts that are used in the same application.
Anything we want to get from the module can be obtained through the Window object. But usually I don't directly copy the contents of the module directly onto the window object, but instead use the content in the module more organized. In most languages, we refer to these containers as "namespaces", which we can simulate in the "object" way in JS.
Name space
If we want to declare a namespace and put a function into this space, the code can be written like this:
1234 |
window.myApp = window.myApp || {}; window.myApp.someFunction = function (){ //so some work }; |
We create an object in the global environment that is used to see if another object already exists, and if it already exists, then we can use it directly, otherwise we need to create a new object with ' {} '. Next, we can start adding the contents of this namespace, putting the various functions into this space, as the code snippet above does, but we don't want these functions to be there, but we want to associate the modules with the namespaces as follows:
123 |
( function (myApp, $, undefined){ //do some work }(window.myApp = window.myApp || {}, jQuery)); |
You can also write this:
1234 |
window.myApp = ( function (myApp, $, undefined){ //do some work return myApp; })(window.myApp || {}, jQuery); |
Now that we are no longer passing the window into our module, we pass a namespace into the module that is associated with the Window object. The reason for using ' | | ' Because we can reuse the same namespace instead of having to recreate it every time we need to use the namespace. Many libraries with namespace methods will help you create spaces, or you can use tools like namespace.js to build nested namespaces. Because in JS, every item in the namespace you have to specify its namespace, so I usually try not to create a deep nested namespace. If you create a dosomething method in MyApp.MyModule.MySubModule , you need to refer to it this way:
1 |
MyApp.MyModule.MySubModule.doSomething(); |
Each time you want to invoke it, or you can give the namespace an alias in your module:
1 |
var MySubModule = MyApp.MyModule.MySubModule; |
After this definition, if you want to use dosomething This method can be called with mysubmodule.dosomething () . But this approach is not necessary, unless you have very, very much code, otherwise this will only complicate the problem.
Secret module mode
You'll often see another design pattern when you create a module: The Secret module pattern (revealing). It is somewhat different from the module pattern: all the content defined in the module is private, and then you can put all the content that is exposed to the outside of the module in an object, and then return the object. You can do this:
1234567891011121314 |
var myModule = (
function
($, undefined){
var myVar1 =
‘‘
,
myVar2 =
‘‘
;
var someFunction =
function
(){
return myVar1 +
" " + myVar2;
};
return {
getMyVar1:
function
() {
return myVar1; },
//myVar1 public getter
setMyVar1:
function
(val) { myVar1 = val; },
//myVar1 public setter
someFunction: someFunction
//some function made public
}
})(jQuery);
|
Create a module at a time, and then return an object containing the module fragments that need to be public, and the variables that need to remain private in the module are not exposed. The mymodule variable contains two common items, but the myVar2 in Somefunction is not available externally.
Create a constructor (class)
There is no concept of "class" in JS, but we can create an "object" by creating a constructor. Let's say we're going to create a series of person objects, we also need to pass in the last name, first name, and age, and we can define the constructor as follows (this part of the code should be placed in the module):
123456789 |
var Person =
function
(firstName, lastName, age){
this
.firstName = firstName;
this
.lastName = lastName;
this
.age = age;
}
Person.prototype.fullName =
function
(){
return this
.firstName +
" " +
this
.lastName;
};
|
Now look at the first function, and you'll see that we've created a person constructor. We use it to construct a new person object. This constructor requires 3 incoming parameters, and then assigns the 3 parameters to the execution context. We also get to the public instance variable in this way. You can also create a private variable: Assign an incoming parameter to a local variable in the constructor. But after doing so, public methods will not be able to get these private variables, so you'd better turn them into public. You can also put the method in the constructor and can get it from the outside, so that the method can get the private variables in the constructor, but in doing so there will be a series of new problems.
In the second method we used the "prototype" (prototype) of the person constructor. The prototype of a function is an object that you need to traverse all instances of this function when you need to parse the field or function that it calls to on an instance. So what these lines of code does is create an instance of the FullName method, and then all instances of the person can call to this method directly, instead of adding a FullName methods, resulting in the flooding of methods. We can also do this in the constructor using
1 |
this .fullName = function () { … |
Way to define FullName, but so each person instance will have a copy of the FullName method, which is not what we want.
If we want to create A person instance, we can do this:
12 |
var person = new Person( "Justin" , "Etheredge" ); alert(person.fullName()); |
We can also create a constructor that inherits from Person: Thespy constructor, we will create an instance of the spy , but only one method is declared:
12345678910111213 |
var Spy =
function
(firstName, lastName, age){
this
.firstName = firstName;
this
.lastName = lastName;
this
.age = age;
};
Spy.prototype =
new Person();
Spy.prototype.spy =
function
(){
alert(
this
.fullName() +
" is spying."
);
}
var mySpy =
new Spy(
"Mr."
,
"Spy"
, 50);
mySpy.spy();
|
As you can see, we've created a constructor that 's very similar to person, but its prototype is an instance of person. Now we have added some methods that allow the spy instance to invoke the person's method, as well as direct access to the variables in the spy . This method is more complex, but once you understand how to use it, your code becomes elegant.
Conclusion
See here, hope you have learned something. However, this article does not introduce much about the "modern" JS development. This article is concerned with the old knowledge, which has been widely used in the past few years. Hope you after reading this article, found the right direction to learn JS. Now it's possible that you put the code into different files in different modules (you should do it!). ), then the next step is to start studying how to combine and compress JS. If you're a developer using Rails 3, you can get this information or tools for free on asset pipeline. If you are. NET developer, you can look at the Squishit framework, which is where I started. If you are a developer of ASP. NET MVC 4, there are related resources as well.
I hope this article will be of help to you. Later I will also introduce the development of modern JS, look forward to the time to see your ID.
"Go" prepares for modern JavaScript development