First-class citizens in the JavaScript world-Functions

Source: Internet
Author: User
In many traditional languages (such as C/C ++/Java/C #), functions exist as second-class citizens, you can only declare a function with the keyword of the language and call it. If you need to pass the function as a parameter to another function, or assign a value to a local variable, or return a value, then... syntaxHighlighter. all ();

Introduction
In many traditional languages (such as C/C ++/Java/C #), functions exist as second-class citizens. You can only declare a function with the keywords of the language and then call it, if you need to pass a function as a parameter to another function, or assign a value to a local variable, or return a value, you need to use the function pointer and proxy (delegate) and so on.

In the JavaScript world, a function is a first-class citizen. It not only has the usage (declaration and call) of all traditional functions, but also can assign values, PASS Parameters, and return values like simple values, such a Function is also called the First-class Function ). In addition, functions in JavaScript also act as class constructor and are also an instance of the Function class ). Such multiple identities make JavaScript Functions very important.

I. Entry-level JavaScript Functions
Similar to common languages, JavaScript Functions follow the principle of first sound and then use. A function name can only contain letters, numbers, underscores, or $, and cannot start with a number. There are two common methods to declare functions:

 

[Javascript]
// Directly declare the function myfunc
Function myfunc (/* arguments */){
}
// Assign an anonymous function to the local variable myfunc
Var myfunc = function (/* arguments */){
}

// Directly declare the function myfunc
Function myfunc (/* arguments */){
}
// Assign an anonymous function to the local variable myfunc
Var myfunc = function (/* arguments */){
}
Note that there are minor differences between the above two function declaration methods: the first method is a named function during the declaration, whether it is before or after the Declaration, even the locations that won't be executed (for example, after the return statement or never in the true Branch) are accessible throughout the scope; the second method is to assign an anonymous function to a variable. Strictly speaking, this is not a function declaration, but a function expression ), this function cannot be accessed by any code before the assignment. That is to say, this assignment must be completed before the call. Otherwise, an error occurs during the call: "TypeError: undefined is not a function ". For example:


[Javascript]
Myfunc1 (); // can be called normally, because myfunc1 adopts the direct declaration method.
Function myfunc1 (){
}
 
Myfunc2 (); // error TypeError: undefined is not a function
 
Var myfunc2 = function (){
}

Myfunc1 (); // can be called normally, because myfunc1 adopts the direct declaration method.
Function myfunc1 (){
}

Myfunc2 (); // error TypeError: undefined is not a function

Var myfunc2 = function (){
}
The basic call method of a function is the same as that of a traditional language. Use a pair of brackets to call the function: myfunc (). JavaScript Functions also support direct or indirect recursive calls. For example, the typical Fibonacci function can be implemented using JavaScript as follows:

 

[Javascript]
Function fib (n ){
If (n = 1 | n = 2 ){
Return 1;
} Else {
Return fib (n-2) + fib (n-1 );
}
}

Function fib (n ){
If (n = 1 | n = 2 ){
Return 1;
} Else {
Return fib (n-2) + fib (n-1 );
}
}
A JavaScript function can handle variable-length parameters. Each function has a local variable named arguments, which is an array-liked object, it contains all the parameters passed in during the call. The length attribute indicates the number of parameters. For example:

 

[Javascript]
Function test (){
Alert (arguments. length );
}
 
Test (1); // 1
Test (1, 'A'); // 2
Test (true, [], {}); // 3

Function test (){
Alert (arguments. length );
}

Test (1); // 1
Test (1, 'A'); // 2
Test (true, [], {}); // 3 use arguments to implement functions similar to C-language printf, or to implement method polymorphism.


Ii. Advanced JavaScript Functions
2.1 anonymous and nested Functions
In JavaScript, you can declare a Function without a name, called an anonymous Function ). At the same time, JavaScript allows you to declare a Function inside a Function, called a Nested Function. The scope of a Nested Function is the entire parent Function.

In the previous part of the function declaration, we can see a usage of anonymous and nested functions. Since anonymous functions do not have names, new variables will not be introduced to pollute the context, in addition, new variable scopes are introduced. Therefore, anonymous functions are often used to prevent global environment pollution.


The JavaScript runtime has a special global object, which stores global functions and variables. In actual development, several third-party libraries or multiple js files are often used, if repeated variables or function declarations are accidentally introduced to the global object, the code execution will be chaotic. For example, if two js files are successively introduced and their own function logs are defined as internal use, the second introduced function will overwrite the first definition and will not throw any errors, calling the log function in subsequent execution may cause errors. At this time, using an anonymous function to wrap the logic of the entire js can avoid this error. This method has been used by the vast majority of Open Source js libraries.

 

[Javascript]
(Function () {// anonymous function
Function log (msg ){
Console. log (msg );
}
// Other code
} (); // Execute now

(Function () {// anonymous function
Function log (msg ){
Console. log (msg );
}
// Other code
} (); // Immediate execution of the above Code is a simple example. The scope of the log function is limited to this anonymous function, while the anonymous function is enclosed by a pair of parentheses () include to form a function expression. The expression value is a function, followed by a pair of parentheses indicating that the function is executed immediately, so that the original code can be executed normally once. However, the declared functions and variables declared through var are internal and cannot be accessed by any code other than anonymous functions. If you need to expose some functions as interfaces, you can use the following methods:

 

[Javascript]
Var mylib = (function (global ){
Function log (msg ){
Console. log (msg );
}
Log1 = log; // Method 1: use the default behavior declared by variables without var to become a global variable in log1 (not recommended)
Global. log2 = log; // Method 2: add the log2 attribute directly to the global object and assign the value to the log function (recommended)
Return {// method 3: obtain a series of interface function set objects through anonymous function return values and assign values to the global variable mylib (recommended)
Log: log
};
} (Window ));

Var mylib = (function (global ){
Function log (msg ){
Console. log (msg );
}
Log1 = log; // Method 1: use the default behavior declared by variables without var to become a global variable in log1 (not recommended)
Global. log2 = log; // Method 2: add the log2 attribute directly to the global object and assign the value to the log function (recommended)
Return {// method 3: obtain a series of interface function set objects through anonymous function return values and assign values to the global variable mylib (recommended)
Log: log
};
} (Window); 2.2 High-order Function)
If a function is used as a parameter or return value, it is called a high-order function. All functions in JavaScript can be used as high-order functions. This is also a feature of the first type of function. Next we will analyze the two usage methods respectively.


[Javascript]
Function negative (n ){
Return-n; // returns the opposite value of n.
}
Function square (n ){
Return n * n; // The square of n
}
Function process (nums, callback ){
Var result = [];
For (var I = 0, length = nums. length; I <length; I ++ ){
Result [I] = callback (nums [I]); // transmits all elements in the array nums to callback for processing, and saves the returned values as results.
}
Return result;
}
Var nums = [-3,-2,-1, 0, 1, 2, 3, 4];
Var n_neg = process (nums, negative );
// N_neg = [3, 2, 1, 0,-1,-2,-3,-4];
Var n_square = process (nums, square );
// N_square = [9, 4, 1, 0, 1, 4, 9, 16];

Function negative (n ){
Return-n; // returns the opposite value of n.
}
Function square (n ){
Return n * n; // The square of n
}
Function process (nums, callback ){
Var result = [];
For (var I = 0, length = nums. length; I <length; I ++ ){
Result [I] = callback (nums [I]); // transmits all elements in the array nums to callback for processing, and saves the returned values as results.
}
Return result;
}
Var nums = [-3,-2,-1, 0, 1, 2, 3, 4];
Var n_neg = process (nums, negative );
// N_neg = [3, 2, 1, 0,-1,-2,-3,-4];
Var n_square = process (nums, square );
// N_square = [9, 4, 1, 0, 1, 4, 9, 16]; the Code above shows an example of passing a function as a parameter to another function called by process, in the implementation of the process function, callback is treated as a black box. It is responsible for passing the parameter to it and obtaining the return value. It is not clear the specific implementation of callback before calling. Only when 20 rows and 22 rows are executed, callback is represented by negative or square, respectively, and the opposite value or square value is taken for each element.


[Javascript]
Function generator (){
Var I = 0;
Return function (){
Return I ++;
};
}
Var gen1 = generator (); // obtain a natural number generator.
Var gen2 = generator (); // obtain another natural number generator.
Var r1 = gen1 (); // r1 = 0
Var r2 = gen1 (); // r2 = 1
Var r3 = gen2 (); // r3 = 0
Var r4 = gen2 (); // r4 = 1

Function generator (){
Var I = 0;
Return function (){
Return I ++;
};
}
Var gen1 = generator (); // obtain a natural number generator.
Var gen2 = generator (); // obtain another natural number generator.
Var r1 = gen1 (); // r1 = 0
Var r2 = gen1 (); // r2 = 1
Var r3 = gen2 (); // r3 = 0
Var r4 = gen2 (); // r4 = 1 [javascript] view plaincopyprint?

The code above shows an example of using a function as the return value. generator is a natural number generator function, and the return value is a natural number generator function. Each time you call generator, an anonymous function is returned as a result. This anonymous function returns each natural number in sequence when called. Variable I in generator increases by 1 every time this anonymous function is called, which is actually a closure. Next we will introduce the closure.


2.3 Closure (Closure)
Closure is not a new concept. Closure is used in many functional languages. In JavaScript, a closure is used when you use variables in the scope of external functions in Embedded functions. A common analogy is used to explain the relationship between a closure and a Class: A Class is a data with a function, and a closure is a function with data.

The variables used in the closure have a feature that they are not released when the parent function returns, but end with the closure lifecycle. For example, in the example of generator in the previous section, gen1 and gen2 use independent variables I (gen2 I is not affected when gen1 I auto-increment 1, and vice versa), as long as gen1 or gen2 variables are not garbage collected by the JavaScript engine, their respective variable I will not be released. In JavaScript programming, the closure will be used without knowing it. This feature of the closure is easy to use, but also easily leads to problems similar to memory leakage. For example:


[Javascript]
Var elem = document. getElementById ('test ');
Elem. addEventListener ('click', function (){
Alert ('You clicked' + elem. tagName );
});

Var elem = document. getElementById ('test ');
Elem. addEventListener ('click', function (){
Alert ('You clicked' + elem. tagName );
}); The purpose of this Code is to display its label name when you click a knot. It registers an anonymous function as a click event handler for a DOM node, the function references a DOM object elem to form a closure. This will generate a circular reference, namely: DOM-> closure-> DOM-> closure... the DOM object will not be released before the closure is released, and the closure exists as the event handler function of the DOM object, so the closure will not be released before the DOM object is released, even if the DOM object is deleted in the DOM tree, because of this circular reference, neither the DOM object nor the closure will be released. The following method can be used to avoid Memory leakage:


[Javascript]
Var elem = document. getElementById ('test ');
Elem. addEventListener ('click', function (){
Alert ('You clicked' + this. tagName); // The elem variable is no longer directly referenced.
});

Var elem = document. getElementById ('test ');
Elem. addEventListener ('click', function (){
Alert ('You clicked' + this. tagName); // The elem variable is no longer directly referenced.
}); Use this in the above Code to replace elem (in the DOM Event Handler function, this pointer points to the DOM element itself ), so that JS runtime does not consider this function to use the parent class variable, so it does not form a closure.
The closure will also cause many similar memory leaks. You only need to pay attention to the closure when writing code to avoid such problems as much as possible.


2.4 class Constructor
JavaScript Functions serve as class constructor at the same time. Therefore, you can use the new keyword to create class instances as long as you declare a function.


[Javascript]
Function Person (name ){
This. name = name;
This. toString = function (){
Return 'hello, '+ this. name + '! ';
};
}
Var p = new Person ('ghostheiaven ');
Alert (p); // Hello, Ghostheaven!

Function Person (name ){
This. name = name;
This. toString = function (){
Return 'hello, '+ this. name + '! ';
};
}
Var p = new Person ('ghostheiaven ');
Alert (p); // Hello, Ghostheaven! In the above example, the Person function is used as the class constructor. In this case, this points to the newly created instance object and adds attributes and methods to the instance, for detailed object-oriented JavaScript programming, You can query other information online. Here I want to talk about the return value of JavaScript Functions when they are used as class constructors.


[Javascript]
Function MyClass (name ){
This. name = name;
Return name; // the return value of the constructor?
}
Var obj1 = new MyClass ('foo ');
Var obj2 = MyClass ('foo ');
Var obj3 = new MyClass ({});
Var obj4 = MyClass ({});

Function MyClass (name ){
This. name = name;
Return name; // the return value of the constructor?
}
Var obj1 = new MyClass ('foo ');
Var obj2 = MyClass ('foo ');
Var obj3 = new MyClass ({});
Var obj4 = MyClass ({}); The above constructor is special. If there is a return statement, then obj1 ~ What objects does obj4 point? The actual result is as follows:
Obj1 = MyClass object
Obj2 = 'foo'
Obj3 = {}
Obj4 = {}

The specific reason is not described in this article. Since constructors with returned values produce strange results, do not call return statements with returned values in Constructors (null return is acceptable ).


Iii. JavaScript function monsters
Welcome to the monster-level function teaching area. Here we will show you how to calmly face the old monsters...


3.1 Function class
During JavaScript running, a built-in class is called Function. Declaring a function with the Function keyword is actually a shorthand form for creating a Function class object, all functions have all functions, such as call, apply, and bind. You can use the instanceof keyword to verify this statement.

Since a Function is a class, its constructor is a Function (it is also an object of the Function class). It should be able to generate a Function object through the new keyword. The first monster came, that is, how to use the Function class to construct a Function. Function Syntax:


[Javascript]
Var func1 = new Function ('name', 'Return "Hello," + name + "! ";');
Func1 ('ghostheave'); // Hello, Ghostheaven!

Var func1 = new Function ('name', 'Return "Hello," + name + "! ";');
Func1 ('ghostheave'); // Hello, Ghostheaven! The above method constructs a Function through function, which is exactly the same as other functions declared with the Function keyword.
Many people may ask why such a monster is needed? "What exists is reasonable." The Function class has its unique purpose. You can use it to dynamically generate various Function logics or replace the functions of eval functions, in addition, the current environment will not be contaminated *.


3.2 Self-update Function)
In many languages, once declared, a function with the same name cannot be declared again. Otherwise, a syntax error occurs. Functions in JavaScript can not only be declared repeatedly, but can also be updated by themselves. Eat your monsters by yourself!
[Javascript]
Function selfUpdate (){
Window. selfUpdate = function (){
Alert ('second run! ');
};
Alert ('first run! ');
}
SelfUpdate (); // first run!
SelfUpdate (); // second run!

Function selfUpdate (){
Window. selfUpdate = function (){
Alert ('second run! ');
};
Alert ('first run! ');
}
SelfUpdate (); // first run!
SelfUpdate (); // second run! This type of function can be used to run the logic only once. After the first operation, it is replaced with a new logic.
Summary
JavaScript Functions are very powerful, and they also bring many negative problems while effectively solving many problems. The use of monster-level functions is generally a little-known method. Unless necessary, it may cause difficulty in reading code and affect the development efficiency of the team.

* The strict mode is introduced in the new ECMAScript. In the strict mode, eval functions are greatly restricted and the environment is not polluted.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.