parameters Function parameters will appear in two places, namely the function definition place and the function call place. The parameters in these two places are different.
Formal parameters (formal parameters)
The parameters that appear in the function definition can be regarded as a placeholder. It has no data and can only wait until the function is called to receive the passed data, so it is called a formal parameter, or formal parameter for short.
Actual parameters (actual parameters)
The parameters given when the function is called contain real data and will be used by the code inside the function, so they are called actual parameters, or actual parameters for short.
The difference and connection between formal parameters and actual parameters
1) Formal parameter variables will only allocate memory when the function is called. After the call is completed, the memory will be released immediately, so the formal parameter variables are only valid inside the function and cannot be used outside the function.
2) Actual parameters can be constants, variables, expressions, functions, etc. No matter what type of data the actual parameters are, they must have certain values when making function calls in order to transfer these values to the formal parameters, so You should use assignment, input and other methods in advance to obtain a certain value for the actual parameters.
3) Actual parameters and formal parameters must be strictly consistent in number, type, and order, otherwise a "type mismatch" error will occur. Of course, if automatic type conversion is possible or forced type conversion is performed, the actual parameter type can also be different from the formal parameter type.
4) The data transfer that occurs in a function call is one-way, and the value of the actual parameter can only be transferred to the formal parameter, but the value of the formal parameter cannot be transferred to the actual parameter in the reverse direction; in other words, once the data transfer is completed , the actual parameters and the formal parameters are no longer related, so during the function call, changes in the value of the formal parameters will not affect the actual parameters.
5) Although formal parameters and actual parameters can have the same name, they are independent of each other and do not affect each other, because actual parameters are valid outside the function, while formal parameters are valid inside the function.
The function of formal parameters and actual parameters is to pass data. When a function call occurs, the value of the actual parameter will be passed to the formal parameter.
function allows us to pass data in, and the passed data affects the function execution results, making the function more flexible and reusable.
function foo(a, b) { console.log([a, b]); } foo(1, 2); //
In this example of output [1, 2], a
and b
are local variables in the function and can only be accessed within the function. When calling the function, the data passed will be matched according to the position and assigned to a
and b
respectively.
When creating a function, the parameters set in parentheses after function 函数名
are called formal parameters ; when calling a function, the parameters passed in parentheses after the function name are called actual parameters . In the above example, a
and b
are formal parameters, and the passed in 1
and 2
are actual parameters.
Because formal parameters are declared variables, they cannot be declared repeatedly with let
and const
.
function foo(a, b) { let a = 1; // Error, a has been declared const b = 1; // Error, b has been declared}
All function transfers in JavaScript are passed by value, not by reference. The so-called value refers to the value stored directly on the variable. If the object is passed as a parameter, then the value is a reference to the object, not the object itself. This is actually an implicit assignment process, so when passing parameters to a function, it is equivalent to assigning values from one variable to another variable .
Original value:
function add(num) { return num + 1; } let count = 5; let result = add(count); // The process of parameter passing here can be regarded as num = count console.log(count); // 5 console.log(result); // 6
reference value:
function setName(obj) { obj.name = "Xiao Ming"; } let person = {}; setName(person); // The process of parameter passing here can be seen as obj = person; console.log(person); // {name: "Xiao Ming"}
Functions in JavaScript will neither detect the type of parameters nor the number of parameters passed in. Setting two formal parameters when defining a function does not mean that two parameters must be passed in when calling. When actually calling, no matter whether one or three parameters are passed, no error will be reported even if no parameters are passed.
There is a special array-like object named arguments
(not an instance of Array
) in all functions (non-arrows), which holds a copy of all actual parameters. We can use it to obtain the values of all actual parameters according to the index access method of the array. value, you can also access its arguments.length
property to determine the number of parameters passed in when the function is actually called.
For example:
function foo(a, b) { console.log(arguments[0]); console.log(arguments[1]); console.log(arguments.length); } foo(10, 20); // Output 10, 20, 2 in sequence.
In the above example, the first parameter of the foo() function is a, and the second parameter is b, which can be obtained separately through arguments[x]. Same value. Therefore, you can even declare a function without setting formal parameters.
function foo() { console.log(arguments[0]); console.log(arguments[1]); } foo(10, 20); // Output 10 and 20 in sequence.
It can be seen that the formal parameters of the JavaScript function are only written for convenience. Passing as many parameters as you want will not cause an error.
Another thing to note is that arguments
can be used together with formal parameters, and the values in the arguments
object will be synchronized with the corresponding formal parameters. For example:
function foo(a) { arguments[0]++; console.log(a); } foo(10); // Output 11 //---------------------------------------- function foo2(a) { a++; console.log(arguments[0]); } foo2(10); // Output 11
When the value of arguments[0] or a is modified, the other one is also changed. This does not mean that they access the same memory address, after all we are passing in a primitive value. They are still separate in memory, but their values are kept in sync due to internal mechanisms.
In addition, if the parameter is missing, the value of this formal parameter will not be synchronized with the corresponding value in the arguments
object. For example, in the following example, only one parameter is passed, so there is only one actual parameter value in arguments
. At this time, if arguments[1] is set to a certain value in the function, this value will not be synchronized to the second formal parameter, for example :
function foo(a,b) { arguments[1] = 2; console.log(b); } foo(1); // Output undefined
In this example, the formal parameter b does not have an actual parameter passed in, and its value will default to undefined
. But if:
foo(1, undefined); //
When output 2 is manually passed in undefined
, an element with a value of undefined
will appear in the arguments
array, which can still be synchronized with the value of b.
In strict mode , the values and formal parameters in the arguments
object will no longer be synchronized. Of course, if reference values are passed in, they will still affect each other, but this is just a characteristic of reference values. Therefore, it is best not to rely on this synchronization mechanism during development, that is, do not use formal parameters and their corresponding values in the arguments
object at the same time.
There are no arguments in arrow functions
. If the function is defined using arrow syntax, there is no arguments object in the function and can only be accessed through the defined formal parameters.
let foo = () => { console.log(arguments[0]); }foo(); // Error, arguments are undefined.
In some cases, arguments
may be accessed:
function fn1(){ let fn2 = () => { console.log(arguments[0]); } fn2(); }fn1(5);
But these arguments
are not from the arrow function, but belong to the external ordinary function. When arguments
are accessed in the arrow function, arguments
of the external function are found along the scope chain.
When a function contains multiple formal parameters, calling the function becomes a trouble, because you always have to ensure that the parameters passed in are placed in the correct position. Is there any way? How to solve the limitation of parameter passing order?
Since object attributes are unordered, the corresponding value is determined by the attribute name. Therefore, you can pass in the object and use the properties in the object as the real parameters, so the order of the parameters does not matter.
function foo(obj) { console.log(obj.name, obj.sex, obj.age); } foo({ sex: 'Male', age: 18, name: 'Xiao Ming' }); // Xiao Ming is male 18
If no actual parameters are provided when calling a function, the default value of the formal parameters is undefined
.
Sometimes we want to set a specific default value. Before ES6, when explicitly setting the default value was not supported, we could only use a workaround:
function sayHi(name) { name = name || 'everyone'; console.log( 'Hello ' + name + '!'); } sayHi(); // Output 'Hello everyone!'
and determine whether there is any assignment by checking the parameter value. Although the above method is simple, the disadvantage is that if the incoming actual parameter corresponds to a Boolean value of false
, the actual parameter will not work. . If you need more precision, you can use an if
statement or a ternary expression to determine whether the parameter is equal to undefined
. If so, it means that the parameter is missing:
// if statement determines the function sayHi(name) { if (name === undefined) { name = 'everyone'; } console.log( 'Hello ' + name + '!'); } //Ternary expression judgment function sayHi(name) { name = (name !== undefined) ? name : 'everyone'; console.log( 'Hello ' + name + '!'); }
ES6 is much more convenient because it supports the explicit way of setting default values, like this:
function sayHi(name = 'everyone') { // When defining a function, directly assign values to the formal parameters console.log( ' Hello ' + name + '!'); } sayHi(); // Output 'Hello everyone!' sayHi('Tony'); // Output 'Hello Tony!' sayHi(undefined); // Output 'Hello everyone!'
These results show that it also determines whether the parameter is missing by whether the parameter is equal to undefined
.
The default value can not only be a value, it can also be any legal expression, even a function call:
function sayHi(name = 'every'+'one') { console.log( 'Hello ' + name + '!'); } sayHi(); // Output 'Hello everyone!' //----------------------------------------- function foo() { console.log('Calling foo'); return 'Tony'; } function sayHi(name = foo()) { console.log( 'Hello ' + name + '!'); } sayHi(); // Output 'call foo' // Output 'Hello Tony!' sayHi(undefined); // Output 'call foo' // Output 'Hello Tony!' sayHi('John'); // Output 'Hello John!'
You can see that the default value of the function parameter will only be evaluated when the function is called and the value of the parameter is missing or undefined
, and will not be evaluated when the function is defined. .
Usually we set default values for parameters so that we can appropriately omit the parameters when calling the function. What should be noted here is that when there are multiple parameters, if the parameter with a default value is not placed at the end, it is actually impossible to omitted.
function fn(x = 1, y) { console.log([x, y]); } fn(); // output[1, undefined] fn(2); //output[2, undefined] fn(, 2); // Error, syntax error (empty slots like arrays are not supported here) fn(undefined, 2); // Output [1, 2] (It is better to pass 1 for convenience!)
In the above example, the default value set for the formal parameter x seems meaningless. Therefore, it is best to put parameters with default values at the end:
function fn(x, y = 2) { console.log([x, y]); } fn(); // output[undefined, 2] fn(1); //output[1, 2] fn(1, 1) //output[1, 1]Parameter omission problem
When multiple parameters have default values set, the problem arises again. You cannot omit the earlier parameters and only pass in the actual parameters to the last parameter.
function fn(x, y = 2, z = 3) { console.log([x, y, z]); } fn(1, , 10) // Report error
We knew earlier that we can avoid the restriction of parameter order by passing in objects. How to implement parameter default values? Using ||
, if
statements or ternary expressions to judge is also a solution, but this seems a bit backward. Next up are two other new methods in ES6.
Parameter default values are used in conjunction with Object.assign()
function fn(obj = {}) { let defaultObj = { x: undefined, y: 2, z: 3 } let result = Object.assign(defaultObj, obj); console.log([result.x, result.y, result.z]); } fn(); // output [undefined, 2, 3] fn({ x: 1, z: 10 }); // Output [1, 2, 10]
In the above example, an object defaultObj
is defined in the function, and the properties in it are used as the default values of the parameters. Then Object.assagin() is used to merge the incoming object and the default object. The properties in defaultObj will be The same attributes of obj are overridden. If there are other attributes in obj, they will be assigned to defaultObj. Here a variable is used to receive the returned merged object.
At the same time, the default value of the formal parameter obj
is also set to an empty object to prevent no parameters from being passed when the function is called, because this will cause the second parameter received by Object.assign() to be undefined
, resulting in an error.
Parameter default values and destructuring assignments are used together
When a function is called, the matching of actual parameters and formal parameters is actually an implicit assignment process. Therefore, parameter passing can also be deconstructed and assigned:
function fn({ x, y = 2, z = 3 }) { console.log([x, y, z]); } fn({}); // Output [undefined, 2, 3] fn({ x: 1, z: 10 }); // Output [1, 2, 10]
In this example, only the default value of the object's destructuring assignment is used, and the default value of the function parameter is not used. If no parameters are passed when the function is called, an error will also be reported, because this will cause the destructuring assignment to fail during parameter initialization, which is equivalent to executing code such as {x, y = 2, z = 3} = undefined
.
Similarly, you can use the syntax of parameter default values to set a default destructuring object for {x, y = 2, z = 3}
, so that functions without passing parameters can be executed smoothly:
function fn({ x, y = 2, z = 3 } = {}) { console.log([x, y, z]); } fn(); // output [undefined, 2, 3]
There are double default values here, which may be a bit confusing. So use a piece of pseudo code to explain the above parameter initialization process :
if(actual parameters=== {...}) { // when fn({...}); { x, y = 2, z = 3 } = {...}; } else if (actual parameter === undefined ){ // when fn(); { x, y = 2, z = 3 } = {}; }
There is one detail that requires special attention to double default values, which is the difference between the default value of destructuring assignment and the default value of function parameter. See the following example:
function fn ({ x = 1 } = {}, { y } = { y: 2 }){ console.log(x, y); } fn(); // Output 1 2 fn({ x: 10 }, { y: 20 }); // Output 10 20 fn({},{}); // 1 undefined
In this function, there are two sets of parameters that use destructuring assignment. It seems that both x and y have default values set. Although they are two different forms, the results are obviously not the same in every case. When the parameter passed in is {}
, y does not get the default value 2. Why is this? Combined with the previous pseudocode example:
fn({ x: 10 }, { y: 20 }); // During initialization: { x = 1 } = { x: 10 }, { y } = { y: 20 } fn({},{}); // During initialization: { x = 1 } = {}, { y } = {}
When the parameter passed in is {}
, the function parameter is not missing or undefined
, so the default value of the function parameter has no effect. At the same time, there are no corresponding values for x and y in {}
. The 1 obtained by x is the default value of destructuring assignment, and y has no default value for destructuring assignment, so it defaults to undefined
.
Scope and temporary dead zone of parameter default values
There is another small detail. Once parameters are set to default values, they will form their own scope (wrapped in (...)
), so variables in the function body cannot be referenced:
function foo(a = b) { let b = 1; } foo(); // Error, b is undefined
But this scope is only temporary. After the parameters are initialized, this scope will no longer exist.
It also follows the rules of ordinary scopes:
let b = 2; function foo(a = b) { let b = 1; return a; } foo(); // 2
In the above example, there is a global variable b, then the formal parameter a will get the value of the global variable b.
Of course, if there is a formal parameter b in the formal parameter scope, it will first obtain the current scope:
let b = 2; function foo(b = 3,a = b) { return a; } foo(); // 3
Set default values for multiple parameters, they will be initialized in order, following the rules of "temporary dead zone", that is, the previous parameters cannot refer to the later parameters:
function foo(a = b, b = 2) { return a + b; } foo(); // Error, b cannot be accessed before initialization
remaining parameters
ES6 provides the **remaining parameters (rest)** syntax ( ...变量名
), which can collect redundant actual parameters of the function (that is, actual parameters that do not correspond to formal parameters), so that there is no need to use arguments
object. Got it. If the formal parameter is used with the ...
operator, it will become an array, and the redundant actual parameters will be put into this array.
Basic usage of remaining parameters:
function sum(a, ...values) { for (let val of values) { a += val; } return a; } sum(0, 1, 2, 3); // 6
In the above example, during parameter initialization, matching is first performed based on the parameter position, 0 is assigned to a, and then the remaining parameters 1, 2, and 3 will be put into the array values.
The following is a comparison example of using arguments
objects and remaining parameters to obtain parameters:
// How to write arguments function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); } // How to write the remaining parameters const sortNumbers = (...numbers) => { return numbers.sort(); }
It can be seen that the remaining parameters are written more concisely. Although arguments
is an array-like object and an iterable object, it is not an array after all. It does not support array methods. When we use arguments
, if we want to call an array method, we must use Array.prototype.slice.call
to convert it to an array first.
The remaining parameters are different from the arguments
object. They are real Array
instances and can easily use the array method. And arrow functions also support remaining parameters.
In addition, using remaining parameters does not affect the functionality of the arguments
object, it can still reflect the parameters passed in when calling the function.
The position of the remaining parameters
The remaining parameter must be the last formal parameter, otherwise an error will be reported.
// Error reporting function fn1(a, ...rest, b) { console.log([a, b, rest]); } //Correct way to write function fn2(a, b, ...rest) { console.log([a, b, rest]); } fn2(1, 2, 3, 4) // Output [1, 2, [3, 4]]
Expand syntax
Previously we knew how to collect redundant parameters into an array, but sometimes we need to do the opposite, such as passing the elements in an array to a function separately instead of passing in an array, like this :
function sum(...values) { let sum = 0; for (let val of values) { sum += val; } return sum; } let arr = [1, 2, 3, 4]; sum(arr); // "01,2,3,4"
The function in the above example will accumulate all the values passed in. If we pass it in an array directly, we will not get the result we want.
In the example, if an array is passed in, the value of values will become [[1, 2, 3, 4]]
, resulting in only one element in the array values, and the type of this element is an array. Then the function return value is the result of adding the value 0
and the array [1, 2, 3, 4]
. The two types are implicitly converted into strings, and then added together. It is a string concatenation. Effect.
To disassemble the array and pass it into the function, it is first impossible to pass in the parameters one by one - sum(arr[0], arr[1], arr[2], arr[3]);
, because it is not always possible You know how many elements there are in the array, and there may be a lot of elements in the array. It is unwise to pass it manually.
It is more feasible to use the apply() method:
sum.apply(null, arr); // 10
But this is not yet the optimal solution, so here comes the key point!
The new **expand syntax (spread)** in ES6 can help us face this situation. It also uses ...变量名
syntax. Although it is the same as the remaining parameter syntax, its purpose is completely opposite. It can split an iterable object into a comma-separated parameter sequence.
When the function is called, its application is as follows:
sum(...arr); // 10 // Equivalent to sum(1,2,3,4);
It can even be used with regular values at will, there is no restriction on the front and rear positions, and multiple iterable objects can be passed in at the same time:
sum(-1, ...arr); // 9 sum(...arr, 5); // 15 sum(-1, ...arr, 5); // 14 sum(-1, ...arr, ...[5, 6, 7]); // 27
The expansion operator ...
is equivalent to completing the operation of manually passing parameters separately for us. The function only knows that the actual parameters received are individual values, and will not have other effects due to the existence of the expansion operator.
Although the above examples are all for arrays, the expansion syntax can do more than that. Other iterable objects such as strings and literal objects can be expanded. For more information, please see → Expansion Syntax
Formal parameters are local variables declared in the function. The actual parameters passed to the function will be assigned to the formal parameters. Function parameter passing is actually an implicit assignment process.
The number of formal parameters and actual parameters may not be equal:
● Formal parameters with missing actual parameters will get the default value undefined
.
● Additional actual parameters can be accessed through the arguments
object, except for arrow functions.
You can pass in the object so that the order of passing parameters is no longer important, and let the properties in the object be used as the real parameters.
ES6's parameter default value—the default value will be obtained only if the parameter value is missing or undefined
when the function is called.
● Parameters that set default values can be omitted only if they are placed in the last position.
● The default value of the formal parameter setting cannot refer to the variables in the function body, but it can refer to the previous formal parameters and external variables.
● Implementing default values through Object.assign() or destructuring assignment can make the method of passing parameters more flexible.
The main difference between remaining parameters and arguments
:
● The remaining parameters only contain those actual parameters that do not have corresponding formal parameters, while arguments
object contains all the actual parameters passed to the function.
● The remaining parameters are real Array
instances, while arguments
are just array-like objects.
Both the remaining parameters and the expansion syntax use ...
operator, in function-related scenarios:
● Appears at the end of the function parameter list and is the remaining parameter.
● Occurs in function calls, it is expansion syntax.
The above is an article that explains the details of parameters in JavaScript functions. For more information, please pay attention to other related articles on the php Chinese website!