The reason why these two types of JavaScript code don’t play by the rules at runtime is that they run in a private block-level context, which results in different results. Now let’s do a concrete analysis;

  • An abnormal condition
{
	function foo(){}
	foo = 1
}
console.log(foo);
Copy the code

The above code is completely different when running on older browsers (IE10 and below) than when running on newer browsers. Regardless of the final run result, let’s first analyze the run steps in the old and new versions. Okay

  • Older browsers:
    • The first step is to create an ECStack for your code to execute
    • Next, a global context EC(G) is formed, then the variable is promoted, and a function foo is declared and defined
    • Code execution, because older browsers do not have block-level context, the code in this code block is executed directly in the global context. The first line of code is already handled when the variable is promoted, skipping the second line of code “foo=1”, where foo is changed from a function to a value of 1
    • Execute console.log(foo) to print the value 1
  • New browser version:
    • The first step is to create the ECStack for the code to execute
    • The second step is to form the global context EC(G), and then the variables are promoted, and this is where things start to change. Here’s how it works:
      • = =In the global context, braces other than functions/objects form a separate block-level private context if let/const/function is present in braces (loop body, judgment body, code block, etc.)= =
      • = =If function is present in braces other than function/object, variable promotion simply declares that it is no longer defined= =
    • Step 3 Variable promotion: According to rule 2 above, function appears in the code block, so only foo is declared in the global context, not defined
    • Step 4 Code execution: According to rule 1 in Step 2, function is present in the code block, so a separate private block-level context is formed, and the parent of this block-level context is the global context.
    • Private context code execution: There is also variable promotion in the newly formed block-level context, so the function foo in the private context is promoted again, this time with declaration + definition.
    • Function foo(){} does not need to be handled in the variable promotion phase, but in order to be compatible with both ES3/ES5 and ES6, a special mechanism is created:
      • = =Map all operations on Foo in the current line of code to a global copy, but consider any subsequent operations on Foo to be private= =
    • Foo is only declared undefined when a global variable is promoted, as follows: foo was declared in the block-level context before function foo(){} was executed, so foo defined here is given a global copy, and global Foo is defined.
    • Continue: foo is assigned a value of 1 in the private context, and the operation is considered private foo, regardless of the global context.
    • In the end, foo in the global is still a function. Print f foo(){}

Function foo(){}” function foo(){}” after foo=1. This is because there are two promotions, both in the global context and in the private block-level context. The steps are basically the same as above, but when the code reaches the second “function foo(){}”, it still follows the rules above: “== maps all operations that the current line of code did to foo to a global copy of ==”, whereas the current line of code assigned foo to 1, so the value of foo in the global copy is also mapped to 1

{
	function foo(){}
	foo = 1
	function foo(){}}console.log(foo);
Copy the code
  • Abnormal condition 2
var x = 1;
function func(x, y = function anonmymous1(){x=2}){
	x = 3;
	y();
	console.log(x);
}
console.log(x);
Copy the code

This problem is not abnormal, according to our normal logic execution can; Note that: The value of the parameter y is a function anonMymous1, and it is created in the context of func, so the scope of anonMymous1 is the context of func. In the context of func, there is a variable x that changes from 5 to 3. When y is executed, there is no variable x in y. So I’m going to look in the upper context, in the context of func, find the variable x, and I’m going to change it to 2, so I’m going to print x in func as 2. The value of the global variable x is still 1, but if we change this code a little bit, we will immediately become a freak problem: we just need to add a var before the value of x=3 in func. See the following:

var x = 1;
function func(x, y = function anonmymous1(){x=2}){
	var x = 3;
	y();
	console.log(x);
}
console.log(x);
Copy the code

Just adding var makes a difference because ECMA has the following specification:

  • If a parameter is defined in a function and the == parameter is given a default value == (regardless of the value and whether the argument is passed)
  • Let /var/const (let/var/const) == (let/var/const)
  • So when the function is executed, in addition to the function itself will form ==A private contextIn addition to ==, a == is formed based on the code in the function body“New block-level Context”==, the scope of this block-level context is that the function formation is private, ==The code in the function is no longer executed, but is executed in a new block-level context= =.
    • If the variable declared in the block-level context has the same name as the parameter in the function private context, the parameter value is synchronized to the variable in the block-level context before the code is executed in the block-level context.

Here is a preliminary analysis:

  • The first step is to open up the ECStack for code execution
  • Form global context EC(G); Variable promotion, declare variable x, declare and define function func
  • Code execution in the global context: x is assigned to 1 and the function func is called
  • Function func execution: Form a private context EC(func)
    • In private context: Initialize scope chain
      (func),>
    • Initialize this
    • Parameter, x is set to 5; Anonymous1 (scope: current context EC(FUNC))
  • The function ends here and forms a new private block-level context EC(B) (scope: current context EC(FUNC))
  • The code in the original function will be executed in the new block-level context EC(B); In the block-level context there is also initialization of the scope chain, variable promotion (declaring the private variable X and synchronizing the value of the parent context X), and code execution
  • Code execution in the block-level context: x is assigned to 3, and y is called, which is not a variable in the current context, so it looks in the parent context EC(FUNC)
  • Function y (anonymous1) execution: form the private context, find that there is no variable X in the private context formed by Y, also look up the superior context EC(FUNC), and change the x value in the superior context to 2.
  • Function y completes execution, memory is freed, and back to the block-level context EC(B), executing code “console.log(x);” Find that x is the private variable in the current context (value 3) and print the result 3 directly.
  • The function completes and returns to the global context. X in the global context has not been affected during the whole process, so it remains the same value of 1