在阮一峰的《es6入门》中,关于函数参数存在默认值时,有如下的代码

// 代码1
var x = 1;
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x);
}

foo() // 3
x // 1
这里按理说开始以为y内部的x指向的是外部环境下的x,即x=1。然而实际却不是。这是作用域的原因。 在es6标准标准中,关于函数参数预设值的实现: >看规范9.2.12 FunctionDeclarationInstantiation部分 If default value parameter initializers exist, a second Environment Record is created for the body declarations. 步骤 27Else, 1.NOTE A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body. 2.Let varEnv be NewDeclarativeEnvironment(env). 3.Let varEnvRec be varEnv's EnvironmentRecord. 大致意思就是在函数的参数存在预设值的时候,会创建一个独立的作用域,整个参数部分都会包含其中。若不存在预设值,则不会创建参数的作用域。
// 代码2
let foo = 'outer';

function bar(func = () => foo) {
  let foo = 'inner';
  console.log(func());
}

bar(); // outer
在上面这种情况下,func = () => foo。由于func内并没有定义foo,在调用func时func会沿着作用域链在外部环境中找foo,所以func()返回outer。而在代码1中,函数参数的作用域中,存在定义的变量x,故foo()执行时,接收赋值的变量是参数作用域中的x而不是foo函数体内定义的x变量。 回到代码1中,函数参数所在的作用域和函数内部的作用域相互独立,所以实际上存在3个变量x。
// 代码3
var x = 1;
function foo(x=2, y = function(){ console.log(x); }) {
  var x = 3;
  y();
  console.log(x);
}
foo() // 2 
      // 3
x;    // 1

还有一个问题是关于作用域。js中,作用域是静态(词法)作用域,即函数和变量的作用域在它们被定义的时候就已经决定了。


// 代码4
var x = 1;
function outer(){
console.log(x);
}
function foo() {
var x = 3;
var f1 = function(){
return x;
}

outer();
return f1;
}
var func = foo(); // 1
func(); // 3

当一个函数内输出或返回一个变量值时,会现在函数内部查找对应的变量,存在即返回。若不存在,则会通过保存的作用域链向外部作用域查找。由于js是静态作用域,所以outer无论在哪儿调用,输出的都是全局作用域下的x(1),f1函数返回的则是foo函数内部定义的x(3)。如果是动态作用域,则outer应该输出3。

参考:
ES6中函数参数默认值为函数的问题?