“Code Tailor “provides technology related information and a series of basic articles for front-end developers. Follow the wechat public account” Rookie of Xiaohe Mountain “to get the latest articles.

preface

Before we get started, we want to let you know that this article is a summary of the “functions” section of the JavaScript language. If you already know the following things, you can skip this section and jump right into the exercises

  • Introduction of function
  • The name of the function
  • Function overloading
  • Function declarations and function expressions
  • Function as value
  • this
  • Recursion of the function

If you are a little bit forgotten about some parts, 👇🏻 is ready for you!

Summary to summarize

Introduction of function

Functions are a core part of any programming language because they encapsulate statements and, once defined, can be executed anywhere, at any time. Functions in ECMAScript are declared using the function keyword, followed by a set of parameters, followed by the function body.

Here is the basic syntax for functions:

function functionName(arg0, arg1,... ,argN) {
 / / expression
}
Copy the code

Here’s an example:

function sayHi(name, message) {
  console.log('Hello ' + name + ', ' + message)
}
Copy the code

A function can be called by its name, and the arguments to be passed to the function are enclosed in parentheses (separated by commas if there are more than one).

Here is an example of calling the function sayHi() :

sayHi('xhs'.'do you study today? ')
Copy the code

Calling this function yields “Hello XHS, do you study today?” . The parameters name and message are concatenated together as strings inside the function and are eventually printed to the console via console.log().

ECMAScript functions do not specify whether or not to return a value, nor do they restrict the type of value returned. Any function can use a return statement at any time to return the value of the function, followed by the value to be returned. The return value can be of any type. Such as:

function sum(num1, num2) {
  return num1 + num2
}
Copy the code

The function sum() adds the two values and returns the result. Note that there is no special declaration that the function returns a value other than the return statement. It can then be called like this:

const result = sum(5.10)
Copy the code

Note that the function stops execution and exits as soon as the return statement is executed. Therefore, the code following the return statement is not executed. Such as:

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

  console.log('Hello world') // Will not be executed
}
Copy the code

In this case, console.log() is not executed because it comes after the return statement, and the interpreter stops executing it once it reaches the return statement.

A function can have multiple return statements, like this:

function subtract(num1, num2) {
  if (num1 < num2) {
    return num2 - num1
  } else {
    return num1 - num2
  }
}
Copy the code

This subtract() function is used to calculate the difference between the two values. If the first value is less than the second, subtract the first from the second; Otherwise, subtract the second from the first. Each branch of the code has its own return statement that returns the correct difference. A return statement can also have no return value. At this point, the function immediately stops execution and returns undefined. This is most often used to prematurely terminate function execution, not to return a value. For example, in the following example, console.log() will not execute:

function sayHi(name, message) {
  return

  console.log('Hello ' + name + ', ' + message) // Will not be executed
}
Copy the code

As a rule of thumb, a function either returns a value or does not. Functions that return values only under certain conditions can be troublesome, especially when debugging.

The name of the function

Function names are Pointers to functions, so they have the same behavior as other variables that contain Pointers to objects. This means that a function can have multiple function names, as shown below:

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

console.log(sum(10.10)) / / 20

let xhsSum = sum

console.log(xhsSum(10.10)) / / 20

sum = null

console.log(xhsSum(10.10)) / / 20
Copy the code

The above code defines a function called sum to find the sum of two numbers. We then declare another variable, xhsSum, and set its value to equal sum. Note that using a function name without parentheses accesses the function pointer name, but does not execute the function. In this case, both xhsSum and sum refer to the same function. A call to xhsSum() can also return the result. Setting sum to null disconnects it from the function. XhsSum () can be called as usual, no problem.

Function parameters

Arguments to ECMAScript functions are different from those in most other languages. ECMAScript functions care neither about the number of arguments passed in nor the data types of those arguments. Just because a function is defined to receive two arguments does not mean that it is called with two arguments. You can pass one, three, or none, and the interpreter will not fail.

This is mainly because the parameters of an ECMAScript function are internally represented as an array. A function always receives an array when called, but it doesn’t care what the array contains. If there’s nothing in the array, that’s fine; If the array has more elements than required, that’s fine.

In fact, when you use the function keyword to define a (non-arrow) function, you can access the Arguments object inside the function and get the value of each argument passed in from it. The Arguments object is an array-like object (but not an instance of Array), so you can access its elements using bracket syntax (the first argument is arguments[0], the second argument is arguments[1]). To determine how many arguments are passed in, visit the arguments.length property. In the following example, the first argument to the sayHi() function is called name:

function sayHi(name, message) {
  console.log('Hello ' + name + ', ' + message)
}
Copy the code

Arguments [0] can be used to get the same parameter values. Therefore, it is possible to rewrite the function without declaring arguments:

function sayHi() {
  console.log('Hello ' + arguments[0] + ', ' + arguments[1])}Copy the code

In the rewritten code, there are no named parameters. The name and message arguments are gone, but the function can still be called. This shows that arguments to ECMAScript functions are written only for convenience, not necessarily. Unlike other languages, named parameters in ECMAScript do not create function signatures that subsequent calls must match. This is because there is no mechanism for validating named parameters. You can also check the number of arguments passed in via the Length property of the Arguments object. The following example shows how the number of arguments passed to a function is printed for each call:

function getArgsNum() {
  console.log(arguments.length)
}

getArgsNum('string'.45) / / 2

getArgsNum() / / 0

getArgsNum(12) / / 1
Copy the code

This example prints 2, 0, and 1 (in order). In this case, developers can pass as many parameters as they want.

Such as:

function getTotle() {
  if (arguments.length === 1) {
    console.log(arguments[0] + 10)}else if (arguments.length === 2) {
    console.log(arguments[0] + arguments[1])
  }
}

getTotle(10) / / 20

getTotle(30.20) / / 50
Copy the code

The function getTotle() increments 10 when passing only one argument, adds up two arguments, and returns. So getTotle(10) returns 20, and getTotle(30,20) returns 50. It’s not quite as clear-cut as actual function overloading, but it’s enough to make up for the lack of ECMAScript in this area.

Another important aspect to understand is that arguments objects can be used with named arguments, such as:

function getTotle(num1, num2) {
  if (arguments.length === 1) {
    console.log(num1 + 10)}else if (arguments.length === 2) {
    console.log(arguments[0] + num2)
  }
}
Copy the code

In this getTotle() function, you use both named arguments and arguments objects. The named parameter num1 holds the same value as Arugments [0], so it doesn’t matter who is used. (Also, num2 holds the same values as arguments[1].) Another interesting aspect of the Arguments object is that its value is always synchronized with the corresponding named arguments. Consider the following example:

function getTotle(num1, num2) {
  arguments[1] = 10

  console.log(arguments[0] + num2)
}
Copy the code

The getTotle() function rewrites the value of the second argument to 10. Since arguments object values are automatically synchronized to the corresponding named arguments, changing arguments[1] also changes the value of num2, so both values are 10. But that doesn’t mean they all access the same memory address, they’re still separate in memory, they just stay in sync.

Also keep in mind that if you pass only one argument and then set arguments[1] to a value, that value will not be reflected in the second named argument. This is because the length of the Arguments object is based on the number of arguments passed in, not the number of named arguments given when the function is defined. For named parameters, the value is undefined if the parameter is not passed when the function is called. This is similar to defining a variable without initialization.

For example, if only one argument is passed to getTotle(), num2 will be undefined. Arguments will have some changes in strict mode. First, assigning arguments[1] as previously does not affect the value of num2. Even if arguments[1] is set to 10, num2 is still the value passed in. Second, trying to override arguments objects in functions results in syntax errors. (The code doesn’t execute either.)

Function overloading

ECMAScript functions cannot be overloaded like traditional programming. In other languages, such as Java, a function can have two definitions, as long as the signature (the type and number of arguments received) is different. As mentioned earlier, ECMAScript functions do not have signatures because parameters are represented by arrays containing zero or more values. Without function signatures, there is no overloading. If two functions with the same name are defined in ECMAScript, the latter will override the first. Consider the following example:

function addSomeNumber(num) {
  return num + 100
}

function addSomeNumber(num) {
  return num + 200
}
let result = addSomeNumber(100) / / 300
Copy the code

Here, the function addSomeNumber() is defined twice. The first version adds 100 to the argument, and the second version adds 200. When this function is called on the last line, 300 is returned because the second definition overrides the first.

Function declarations and function expressions

We can construct a function by using function or assign a variable to a function, both of which work normally in most cases. However, the JavaScript engine treats function declarations and function expressions differently when loading data. Before any code executes, the JavaScript engine reads the function declaration and generates the function definition in the execution context. A function expression, on the other hand, must wait until the code executes to its line before generating the function definition in the execution context. Consider the following example:

/ / no problem
console.log(sum(10.10))

function sum(num1, num2) {
  return num1 + num2
}
Copy the code

The above code works because the function declaration is read and added to the execution context before any code is executed. This process is called function declaration promotion. When executing code, the JavaScript engine first performs a scan, elevating the found function declaration to the top of the source tree. So even if function definitions appear after the code that calls them, the engine pushes the function declarations to the top. If we change the function declaration from the previous code to an equivalent function expression, we will get an error:

/ / will go wrong
console.log(sum(10.10))

var sum = function (num1, num2) {
  return num1 + num2
}
Copy the code

Function as value

Because function names are variables in ECMAScript, functions can be used anywhere variables can be used. This means that you can not only pass a function as an argument to another function, but also return another function within one function.

function add10(num) {
  return num + 10
}
let result1 = callSomeFunction(add10, 10)
console.log(result1) / / 20
function getGreeting(name) {
  return 'Hello, ' + name
}
let result2 = callSomeFunction(getGreeting, 'Nicholas')
console.log(result2) // "Hello, Nicholas"
Copy the code
function fun1(x) {
  return function (y) {
    return function (z) {
      console.log(x * y * z)
    }
  }
}
fun1(2) (3) (4) / / 24
Copy the code

this

This is a special object that behaves differently in standard and arrow functions.

In standard functions, this refers to the context object in which the function is called as a method, and is usually referred to as this (this refers to the window object when the function is called in the global context of a web page). Consider the following example:

window.color = 'red'

let o = {
  color: 'blue',}function sayColor() {
  console.log(this.color)
}

sayColor() // 'red'

o.sayColor = sayColor

o.sayColor() // 'blue'
Copy the code

The function sayColor(), defined in the global context, references this object. Which object this refers to cannot be determined until the function is called. Therefore, this value may change during code execution. If you call sayColor() in a global context, the result will print red because this refers to window, and this.color equals window.color. After assigning sayColor() to o, call o.saycolor (). This points to O, meaning this.color equals O.color, so it shows blue.

In arrow functions, this refers to the context in which the arrow function is defined. The arrow functions are covered in more detail in part 2’s function extensions.

Recursion of the function

Recursive functions usually take the form of a function calling itself by name, as shown in the following example:

function factorial(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * factorial(num - 1)}}Copy the code

This is a classic recursive factorial function. This is fine, but if you assign this function to another variable, you get a problem:

let anotherFactorial = factorial

factorial = null

console.log(anotherFactorial(4)) / / an error
Copy the code

Here the factorial() function is saved in another variable, anotherFactorial, and factorial is set to null, leaving only a reference to the original function. When you call anotherFactorial(), you recursively call factorial(), but because it’s no longer a function, you get an error. Using arguments.callee when writing recursive functions can avoid this problem. Arguments.callee is just a pointer to the executing function, so it can be called recursively inside the function, as follows:

function factorial(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * arguments.callee(num - 1)}}Copy the code

Replacing the function name with arguments.callee ensures that no matter what variable is used to call the function, there will be no problem. Arguments.callee is therefore the preferred reference to the current function when writing recursive functions. However, code running in strict mode does not have access to arguments.callee because accessing it would cause an error. In this case, you can use named function expression for this purpose. Such as:

const factorial = function f(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * f(num - 1)}}Copy the code

The title self-test

One: What does the following code output

function callFunc(func, argument) {
  return func(argument)
}
function func1(argument) {
  console.log(argument + '. ')
}
callFunc(func1, 'hello,world')
Copy the code
Answer

Answer: ‘hello,world.’

The callFunc function essentially takes the first argument and passes the second argument to the first argument.


Two: What does the following code output

function recursion(num) {
  if (num === 0) return 1
  else if (num % 2= = =0) return recursion(num - 1) + 1
  else return recursion(num - 1)}console.log(recursion(6))
Copy the code
Answer

Answer: 4

Recursion is a recursive function that returns 1 if num equals 0, +1 before the next result if num is even, and odd. It counts the number of even numbers from 0 to num. So recursion(6) is 4


Three: what does the two pieces of code output when executed separately

func1(1.2)
function func2(x, y) {
  console.log(x + y)
}
let func1 = func2
Copy the code
func2(1.2)
function func2(x, y) {
  console.log(x + y)
}
Copy the code
Answer

Func1 (1,2) prints a ReferenceError because func1 has not been defined and assigned at the time of the call. Func2 (1,2) prints 3 because function is declared earlier and can be used before.

JavaScript series of functions, we end here, thank you for your support to the author! Your attention and praise will be the strongest motivation for us to move forward! Thank you!