Function Declaration and Function Expression

There are mainly three ways to define a function, function declaration, function expression, and the new Function constructor. Function declaration and function expression are the more commonly used methods, while the constructor way can be used to define a function from a string.

Function Declaration

Function declaration hoists both the declaration and assignment, which means the entire function body is hoisted to the top of the scope.

s(); // 1
function s(){
    console.log(1);
}

This means that a function defined within a certain scope can be called from any position within that scope, and the entire function body will be hoisted. However, there are exceptions:

console.log(s); // undefined // The function declaration is hoisted but the function body is not assigned
console.log(ss); // Uncaught ReferenceError: ss is not defined // Printing an undefined ss to demonstrate the hoisting of function declarations
s(); // Uncaught TypeError: s is not a function
if(1){
    function s(){
        console.log(1);
    }
}

Here, we can see that the function declaration is hoisted, but the function body is not. JavaScript only has function scope, global scope, and the block scope introduced in ES6 with let and const. In this case, there is no issue with the if scope, as it's within the same scope. However, since the interpreter cannot determine the content inside the if during the preprocessing, it only hoists the function declaration variable and does not assign the function body.

Function Expression

Function expression only hoists the variable declaration, essentially hoisting the variable and assigning an anonymous function object to it.

console.log(s); // undefined
var s = function s(){
    console.log(1);
}
console.log(s);  // f s(){console.log(1);}

From this, we can see that there is a priority relationship between directly declaring a function and declaring a function through function expression.

var s = function(){
    console.log(0);
}
function s(){
    console.log(1);
}
s(); // 0

In JavaScript, functions are first-class citizens. In the book "You Don't Know JavaScript" (Volume I), on page 40, it is mentioned that functions are hoisted first, and then variables. This means that within the same scope, functions are hoisted first. Thus, the execution priority in JavaScript is function declaration, variable declaration, and variable assignment.

function s(){ // Function declaration
    console.log(1);
}

var s; // Variable declaration

// Function has been declared as `a`, the same variable name `var` declaration will be directly ignored
console.log(s); // f s(){...}  

s = function(){ // Variable assignment
    console.log(0);
}

s(); // 0

new Function

The new Function way can parse a string into a function.

var s = new Function("a","b","console.log(a,b);");
s(1,2); // 1,2
console.log(s.__proto__ === Function.prototype); //true
function ss(){} // Declared functions are instances of Function
console.log(ss.constructor === Function); // true
console.log(ss.__proto__ === Function.prototype); // true

new Function differs from eval in its determination of the execution environment for the parsed content.

// The scope of code execution in eval is the current scope, it can access local variables within the function and traverse up the scope chain.
// The scope of code execution in new Function is the global scope, it cannot access local variables within the function.
var a = 'Global Scope';
(function b(){
    var a = 'Local Scope';
    eval("console.log(a)"); //Local Scope
    (new Function("console.log(a)"))() //Global Scope
})();

Daily Exercise

https://github.com/WindrunnerMax/EveryDay

References

https://www.cnblogs.com/echolun/p/7612142.html https://www.cnblogs.com/miacara94/p/9173843.html https://blog.csdn.net/qq_41893551/article/details/83011752