js reference type -- Function type

Functions are actually objects. Each function is an instance of the Function type and has properties and methods like any other reference type. Since functions are objects, the function name is actually a pointer to the function object and is not bound to a function. Functions are usually defined using function declaration syntax, as shown in the following example.
function sum (num1, num2) {
    return num1 + num2;
}
This is almost identical to how functions are defined below using function expressions.
var sum = function(num1, num2){//When using a function expression to define a function, it is not necessary to use the function name, the function can be referenced through the variable sum
    return num1 + num2;
};
Since function names are just pointers to functions, function names are no different from other variables that contain pointers to objects. In other words, a function may have multiple names, as shown in the following 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

The above code first defines a function called sum() to sum two values. Then, the variable anotherSum is declared and set equal to sum (the value of sum is assigned to anotherSum). Note that using a function name without parentheses accesses the function pointer, not the function . At this point, both anotherSum and sum point to the same function, so anotherSum() can also be called and return the result. Even if sum is set to null, making it "disconnected" from the function, anotherSum() can still be called normally.

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 that the latter function overrides the former. 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

When you create the second function, you actually overwrite the variable addSomeNumber that references the first function.

The difference between function declarations and function expressions
In fact, the parser does not treat function declarations and function expressions the same 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. See the example below.

console.log(sum(10,10));
function sum(num1, num2){
    return num1 + num2;
}
The above code works perfectly fine. 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 an equivalent function expression, as in the example below, will result in an error during execution.
console.log(sum(10,10));
var sum = function(num1, num2){
    return num1 + num2;
};

The above code produces an error at runtime because the function is in an initialization statement, not a function declaration. That is, until the statement where the function is located, the variable sum will not hold a reference to the function; moreover, since the first line of code will cause an error, it will not actually execute to the next line. Aside from the difference of when a function can be accessed through a variable, the syntax of a function declaration and a function expression are actually 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);//Return the result after executing the first parameter
}
This function accepts two parameters. 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"
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() is add10 and getGreeting, not the result of executing them.
Returning from one function to another is an extremely 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 accepts 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

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.

function internal properties

Inside a function, there are two special objects: arguments and this . Among them, arguments is an array-like object (not an array), which contains all the parameters passed into the function, it only works inside the function, and always points to all the parameters passed in by the caller of the current function. The arguments object also has a property called callee , which is a pointer to the function that owns the arguments object. Accessing arguments.callee when the function is running in strict mode causes an error and is not recommended.

function test(x) {
    console.log('x = ' + x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
    }
}
test(10, 20, 30);

With arguments, you can get all the arguments passed in by the caller. Even if the function does not define any parameters, you can still get the value of the parameter:

function abs() {
    if (arguments.length === 0) {
        return 0;
    }
    var x = arguments [0];
    return x >= 0 ? x : -x;
}
abs(); // 0
abs(10); // 10
abs(-9); // 9

Another special object inside a function is this, which behaves roughly like this in Java and C#. this refers to the environment object that the function data executes against —or the this value (when calling the function 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(){//Functions defined in the global scope
    console.log(this.color);//The value of this is not determined until the function is called, so this may refer to different objects during code execution
}
sayColor(); //"red"
o.sayColor = sayColor;
o.sayColor(); //"blue"

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". Readers must keep in mind that the name of a function is just a variable containing a pointer. Therefore, even if executed in different environments, the global sayColor() function and o.sayColor() still point to the same function.

Function Properties and Methods
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. 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 ES5, 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. E.g:
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 an array
}
console.log(callSum1(10,10)); //20
console.log(callSum2(10,10)); //20
In the above example, callSum1() passes this as the this value when executing the sum() function (because it is called in the global scope, the window object is passed in) and the 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.
In strict mode, if the function is called without specifying an environment object, the this value will not be converted to window. Unless you explicitly add a function to an object or call apply() or call(), the this value will be undefined.
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, and 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 using the call() method, callSum() must pass each parameter explicitly. 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 are going to pass in the arguments object directly, or if the first received in the containing function is also an array, then it is definitely more convenient to use apply(); otherwise, call() may be more appropriate. (It doesn't matter which method is used without passing arguments to the function.)

For ordinary function calls, we usually bind this to null. For example, to call Math.max(3, 5, 4), use apply() and call() respectively to achieve the following:

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
In fact, passing arguments isn't really where apply() and call() come in; their real power is their ability to expand the scope in which the function runs. Let's look at an example.
window.color = "red";
var o = { color: "blue" };
function sayColor(){ //function defined in the global scope
    console.log(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue (the this object in the function body points to o at this time)
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.
ES5 also defines a method: bind(). This method creates an instance of the function whose this value is bound to the value passed to the bind() function. E.g:
window.color = "red";
var o = { color: "blue" };
function sayColor(){
    console.log(this.color);
}
var objectSayColor = sayColor.bind(o); //sayColor() calls bind() and passes in the object o
objectSayColor(); //blue
The this value of the objectSayColor() function is equal to o, so even if you call this function in the global scope, you will see "blue".
Browsers that support the bind() method are IE9+, Firefox 4+, Safari 5.1+, Opera 12+ and Chrome.
The toLocaleString() and toString() methods that each function inherits always return the function's code. The format of the return code varies by browser - some return the same code as the function code in the source code, while others return the internal representation of the function code, i.e. with the parser stripped of comments and modified by some code. Modified code. Because of these differences, we cannot implement any significant functionality based on the results returned by these two methods; however, this information can be useful when debugging code. The other inherited valueOf() method also returns only the function code.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324538634&siteId=291194637