(Turn) function learning

https://github.com/stone0090/javascript-lessons/tree/master/1.9-FunctionObjects

Skip to content
Personal Open source Business Explore
Sign upSign inPricingBlogSupport
This repository
Search
Watch 66  Star 693  Fork 106 stone0090/javascript-lessons
Code  Issues 0  Pull requests 0  Projects 0  Pulse  Graphs
Branch: master  Create new file Find file History javascript-lessons/1.9-FunctionObjects/
Latest commit 5974374  on 23 Oct  stone finish chapter 2.5
..
Answer.md finish answers of exist lessons. 4 months ago
README.md finish chapter 2.5 2 months ago
README.md
函数

A function is a piece of code that is defined only once, but can be executed or called any number of times. In JavaScript, functions are objects, and programs can manipulate them at will. For example, you can assign functions to variables, pass them as parameters to other functions, set properties on them, and even call their methods. If a function is mounted on an object as a property of the object, it is called a method of the object. If functions are defined nested within other functions, they can access any variables in the scope in which they were defined.

Function Definition

In JavaScript, functions are actually objects, and each function is an instance of the Function constructor, so a function name is actually a pointer to a function object, not bound to a function. Functions are usually defined in the following three ways. For example:

// Writing method 1: function declaration (recommended writing method)
function sum (num1, num2) {
    return num1 + num2;
}

// writing method 2: function expression (recommended writing method)
var sum = function(num1, num2){
    return num1 + num2;
};

// Writing method 3: Function constructor (not recommended writing method)
var sum = new Function("num1", "num2", "return num1 + num2");
Since the function name is only a pointer to the function , so the function name is no different from other variables that contain pointers to objects. In other words, a function may have multiple names. For example:

function sum(num1, num2){
    return num1 + num2;
}
console.log(sum(10,10)); // 20

var anotherSum = sum;
console.log(anotherSum(10,10)); // 20

sum = null;
console.log(anotherSum (10,10)); // 20
No overloading Thinking

of function names as pointers also helps to understand why there is no concept of function overloading in JavaScript.

function addSomeNumber(num){
    return num + 100;
}

function addSomeNumber(num) {
    return num + 200;
}

var result = addSomeNumber(100); // 300
Obviously, this example declares two functions with the same name, and the result is It is the latter function that overrides the former function. The above code is actually no different from the code below.

var addSomeNumber = function (num){
    return num + 100;
};

addSomeNumber = function (num) {
    return num + 200;
};

var result = addSomeNumber(100); // 300
It's easy to understand by rewriting the code that when you create the second function, you actually overwrite the variable addSomeNumber that references the first function.

Function Declarations and Function Expressions The

parser does not treat "function declarations" and "function expressions" the same way when loading data into the execution environment. The parser will read the function declaration first and make it available (accessible) before any code is executed; as for the function expression, it will not be actually interpreted until the parser reaches the line of code it is on. For example:

console.log(sum(10,10)); // 20
function sum(num1, num2){
    return num1 + num2;
} The
above code works perfectly. Because before the code starts executing, the parser has gone through a process called function declaration hoisting to read and add function declarations to the execution environment. When evaluating code, the JavaScript engine declares functions on the first pass and places them at the top of the source tree. So even if the code that declares the function comes after the code that calls it, the JavaScript engine can hoist the function declaration to the top. Changing the above "function declaration" to the equivalent "function expression" will cause an error during execution. For example:

console.log(sum(10,10)); // Uncaught TypeError: sum is not a function
var sum = function(num1, num2){
    return num1 + num2;
};
Except for the above differences, the syntax of "function declaration" and "function expression" are equivalent.

Functions as values

​​Because function names in JavaScript are themselves variables, functions can also be used as values. That is, not only can one function be passed to another function as an argument, but one function can be returned as the result of another function. Take a look at the function below.

function callSomeFunction(someFunction, someArgument){
    return someFunction(someArgument);
}
This function accepts two arguments. The first argument should be a function, and the second argument should be a value to pass to the function. Then, the function can be passed as in the example below.

function add10(num){
    return num + 10;
}

var result1 = callSomeFunction(add10, 10);
console.log(result1); // 20

function getGreeting(name){
    return "Hello, " + name;
}

var result2 = callSomeFunction(getGreeting, "Nicholas");
console.log(result2); // "Hello, Nicholas"
The callSomeFunction() function here is generic, that is, no matter what function is passed in the first parameter, it will return the result of executing the first parameter. To access a pointer to a function without executing the function, the parentheses after the function name must be removed. So in the above example what is passed to callSomeFunction() are add10 and getGreeting, not the result of executing them.

Of course, it is also possible to return from one function to another, and this is a very useful technique. For example, suppose there is an array of objects, and we want to sort the array based on some object property. The comparison function passed to the array sort() method takes two parameters, the value to be compared. However, we need a way to indicate which property to sort by. To solve this problem, you can define a function that receives an attribute name, and then creates a comparison function based on the attribute name. The following is the definition of this function.

function createComparisonFunction(propertyName) {
    return function(object1, object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if (value1 < value2){
            return -1;
        } else if (value1 > value2){
            return 1;
        } else {
            return 0;
        }
    };
}
This function definition looks a bit complicated, but in fact it is nothing more than nesting another function in one function, and adding a return operator in front of the inner function. After the inner function receives the propertyName parameter, it uses square bracket notation to get the value of the given property. Once you have the desired property value, defining the comparison function is very simple. The above function can be used as in the example below.

var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];

data.sort(createComparisonFunction("name"));
console.log(data[0]. name); // Nicholas

data.sort(createComparisonFunction("age"));
console.log(data[0].name); // Zachary
Here, we create an array data that contains two objects. Among them, each object contains a name property and an age property. By default, the sort() method calls each object's toString() method to determine their order; however, the results are often not in line with human thinking habits. Therefore, we call the createComparisonFunction("name") method to create a comparison function to sort by the value of each object's name property. And the first item in front of the result is the object whose name is "Nicholas" and whose age is 29. Then, we use the comparison function returned by createComparisonFunction("age") , this time sorted by the object's age property. The result is that the object whose name is "Zachary" and whose age is 28 comes first.

Formal and actual parameters

of functions Inside functions, there are two special objects: arguments and this. Among them, arguments is an array-like object that contains all the parameters passed into the function. Although the main purpose of arguments is to hold function arguments, this object also has a property called callee, which is a pointer to the function that owns the arguments object. Take a look at this very classic factorial function below.

function factorial(num){
    if (num <= 1) {
        return 1;
    } else {
        return num * factorial(num-1)
    }
}
Defining a factorial function generally requires a recursive algorithm. As shown in the above code, if the function has a name and the name will not change in the future, there is no problem with this definition. But the problem is that the execution of this function is tightly coupled with the function name factorial. To remove this tight coupling, arguments.callee can be used as follows.

function factorial(num){
    if (num <=1) {
        return 1;
    } else {
        return num * arguments.callee(num-1)
    }
}
In the function body of this rewritten factorial() function, there is no more reference The function name factorial. This way, the recursive call is guaranteed to complete normally, regardless of the name used to refer to the function. For example:

var trueFactorial = factorial;

factorial = function(){
    return 0;
};

console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0
Here, the variable trueFactorial gets the value of factorial, actually holding a pointer to a function in another location. Then, we assign a function that simply returns 0 to the factorial variable. Calling trueFactorial() will return 0 if arguments.callee is not used as in the original factorial(). However, after decoupling the code in the function body from the function name, trueFactorial() can still calculate the factorial normally; as for factorial(), it is now just a function that returns 0.

Another special object inside a function is this, which behaves roughly like this in Java and C#. In other words, this refers to the environment object in which the function data is executed (when the function is called in the global scope of the web page, the this object refers to the window). Take a look at the example below.

window.color = "red";
var o = { color: "blue" };

function sayColor(){
    console.log(this.color);
}
sayColor(); // "red"

o.sayColor = sayColor;
o .sayColor(); // "blue"
The function sayColor() above is defined in the global scope, which refers to the this object. Since the value of this is not determined until the function is called, this may refer to a different object during code execution. When sayColor() is called in the global scope, this refers to the global object window; in other words, evaluating this.color translates to evaluating window.color, which returns "red". And when this function is assigned to object o and o.sayColor() is called, this refers to object o, so evaluating this.color is converted to evaluating o.color, which returns "blue".

Please keep in mind that the name of a function is just a variable containing a pointer. Therefore, the global sayColor() function and o.sayColor() point to the same function even if executed in different environments.

ECMAScript 5 also normalizes the property caller of another function object. This property holds the "reference to the function that called the current function". If the current function is called in the global scope, its value is null. For example:

function outer(){
    inner();
}

function inner(){
    console.log(arguments.callee.caller);
}

outer();
The above code will cause the source code of the outer() function to be displayed in the alert box. Because outer() calls inter(), arguments.callee.caller points to outer().

In strict mode, accessing the arguments.callee property, or assigning a value to the function's caller property, will result in an error.

Properties and Methods

of Functions Functions in JavaScript are objects, so functions also have properties and methods. Each function contains two properties: length and prototype. Among them, the length property represents the number of named parameters the function expects to receive, as shown in the following example.

function sayName(name){
    console.log(name);
}

function sum(num1, num2){
    return num1 + num2;
}

function sayHi(){
    console.log("hi");
}

console.log(sayName.length ); // 1
console. log(sum. length); // 2
console. log(sayHi. length); // 0
For reference types in JavaScript, the prototype is the real place to hold all of their instance methods. In other words, methods such as toString() and valueOf() are actually stored under the prototype name, but accessed through instances of their respective objects. The role of the prototype property is extremely important when creating custom reference types and implementing inheritance. In ECMAScript 5, the prototype property is not enumerable, so cannot be discovered using for-in.

Each function contains two non-inherited methods: apply() and call(). The purpose of these two methods is to call the function in a specific scope, which is actually equivalent to setting the value of the this object in the function body. First, the apply() method takes two parameters: a scope in which to run the function, and an array of parameters. Among them, the second parameter can be an instance of Array, it can also be the arguments object. For example:

function sum(num1, num2){
    return num1 + num2;
}

function callSum1(num1, num2){
    return sum.apply(this, arguments); // pass in the arguments object
}

function callSum2(num1, num2){
    return sum.apply(this, [num1, num2]); // pass in array
}

console.log(callSum1(10,10)); // 20
console.log(callSum2(10,10)); // 20
In the above example, callSum1() passes in this when executing the sum() function (because it is called in the global scope, it is passed in is the window object) and arguments object. And callSum2 also calls the sum() function, but it passes in this and an array of parameters. Both functions execute normally and return correct results.

The call() method works the same as the apply() method, the only difference between them is the way they receive parameters. For the call() method, the first parameter is that the value of this does not change, the change is that the rest of the parameters are directly passed to the function. In other words, when using the call() method, the parameters passed to the function must be listed one by one, as shown in the following example.

function sum(num1, num2){
    return num1 + num2;
}

function callSum(num1, num2){
    return sum.call(this, num1, num2);
}

console.log(callSum(10,10)); // 20
In the case of the call() method, callSum() must be passed explicitly for each parameter. The result is no different from using apply(). As for whether to use apply() or call(), it all depends on which method is most convenient for you to pass parameters to the function. If you're going to pass in the arguments object directly, or if the containing function receives an array first, then it's definitely more convenient to use apply(); otherwise, call() may be more appropriate. (It doesn't matter which method you use if you don't pass arguments to the function.) In fact, passing arguments isn't really where apply() and call() come in; their real power is in being able to extend the function on which to run scope. Let's look at an example.

window.color = "red";
var o = { color: "blue" };

function sayColor(){
    console.log(this.color);
}
sayColor(); // red

sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue
This example is modified from the previous example illustrating the this object. This time, sayColor() is also defined as a global function, and when it's called in the global scope, it does print "red" because evaluating this.color translates to evaluating window.color . And sayColor.call(this) and sayColor.call(window) are two ways to explicitly call a function in the global scope, and the result will of course show "red". However, when you run sayColor.call(o), the execution environment of the function is different, because the this object in the function body points to o, so the result is "blue".

The biggest advantage of using call() or apply() to expand the scope is that the object does not need to have any coupling relationship with the method. In the first version of the previous example, we first put the sayColor() function in the object o, and then called it through o; in the example rewritten here, the previous redundant step is not needed .

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327008337&siteId=291194637