False Begginer - 5. 参数默认值、递归、预编译、暗示全局变量

108 阅读5分钟

5.1 函数初始化参数

5.1.1 函数初始化参数,默认值:undefined

// ES6 写法
function fn(a = 1, b) {
	console.log(a, b); 
}
fn(1); // 1 undefined

5.1.2 默认值的取值条件

function fn(a = 1, b) {
  // 为什么打印的a打印的是1,而不是undefined?
		console.log(a, b); // 1 2
}
fn(undefined, 2);

// 默认值的取值:
//1.如果形式参数是undefined,那就取值arguments实参的值
//2.如果形式参数不是undefined,实参是undefined,就取形式参数的值
//3.相当于,形参和实参有一方是undefined,那就取另一方的值作为默认值

// 例子
function fn(a, b) {
	console.log(a, b); // 1 undefined
}
fn(1);

function fn(a = 1, b) {
	console.log(a, b); // 1 1
}
fn(undefined, 1);

function fn(a, b) {
  a = 3;
  b = 4;
  console.log(a, b); // 3 4
}
fn();

5.1.3 默认值与实参/形参的注意事项

function fn(a, b) {
	a = 3; // 和fn(a = 3, b = 4)没区别
	b = 4;
	console.log(a, b); // 3 4
  
// 函数形式参数没有和实参产生对应关系,导致更改形参,实参的映射的值不发生改变,只有传递的实参和形参一一对应,才自动设置映射,二者才能随着改变
  console.log(arguments[0],arguments[1]); // undefined undefined
}
fn();

5.1.4 低版本默认值的写法

function fn(a, b) {
	var a = arguments[0] || 1;
  var b = arguments[1] || 2;
  console.log(a, b); // 1 2
}
fn();

// 三元运算符
function fn(a, b) {
	var a = typeof(a) === 'undefined'? 2 : arguments[0];
  var b = typeof(b) === 'undefined'? 2 : arguments[1];
  console.log(a, b);
}
fn();

5.2 递归

5.2.1 递归的两个要素:

1.递归的规律

2.递归的出口,递归的return值一直在等待着计算结果,然后逐步返回上层的输出结果

5.2.2 递归例题

1. 输出N的阶乘

var n = parseInt(window.prompt('N=?'));
function factorial(n) {
  // 错误机制
  if(n <= 0) {
  	return '输入有误';
  }
	// 递归出口
  if(n === 1) {
  	return 1;
  }
  return n * factorial(n - 1);
}
var num = factorial(n);
console.log(num);

// 执行过程形成的队列
factorial(5) = factorial(4) * 5;
factorial(4) = factorial(3) * 4;
factorial(3) = factorial(2) * 3;
factorial(2) = factorial(1) * 2;
factorial(1) = 1;

2. 输出斐波那契数列的N位

var n = parseInt(window.prompt('N=?'));
function fobo(n) {
  // 错误机制
  if(n < 1) {
  	return '输入有误';
  }
	if(n === 1 || n === 2) {
  	return 1;
  }
  return fobo(n - 1) + fobo(n - 2);
}
var num = fobo(n);
console.log(num);

// 执行过程中的形成的队列
fobo(5) = fobo(4) + fobo(3);
fobo(4) = fobo(3) + fobo(2);
fobo(3) = fobo(2) + fobo(1);
fobo(2) = 1;
fobo(1) = 1;

5.3 预编译

5.3.1 JavaScript引擎解析代码的执行顺序

  1. 检查通篇的代码语法错误,如果有则直接抛出语法错误(任何代码不执行),没有则进行第2步
  2. 进行预编译
  3. 解释一行,执行一行

5.3.2 暗示全局变量(imply global variable)

// 没有用var声明的变量是全局变量

// 在全局环境下,变量和方法都是挂载到window对象上,相当于window对象的属性和方法
var a = 3;
var b = 4;
--->
  window = {
		a : 3,
  	b : 4
	}

// 为什么window.c一个不存在的属性是undefined,而直接打印console.log(c)一个不存在的属性报错(Uncaught ReferenceError: c is not defined)呢?
// 解析: 因为window.c是属于对象语法的性质,在通过window.c形式调用不存在的属性返回的就是undefined。

5.3.3 AO(activation object)活跃对象,函数上下文

1. 在AO中JavaScript引擎预编译的步骤

      1. 寻找函数的形参和变量声明
      2. 实参的值赋值给形参
      3. 寻找函数声明
      4. 执行函数

2. AO例题:

function test(a, b) {
	console.log(a); // 1
  c = 0;
  var c;
  a = 5;
  b = 6;
  console.log(b); // 6
  function b(){};
  function d(){};
  console.log(b); // 6
}
test(1);

// 预编译
// AO = {
	 a:undefined,
     ---> 1
		 ---> 5
   b:undefined,
     ---> function b(){}
		 ---> 6
   c:undefined,
     ---> 0
   d:function d(){}
}

5.3.4 GO(global object)全局上下文

1. 在GO中JavaScript引擎预编译的步骤

      1. 寻找变量声明
      2. 寻找函数声明
      3. 执行赋值

2. GO全局上下文与window对象相等 GO===window

3. 函数表达式和函数声明和对象的匿名函数提升问题

// 函数声明会在GO中JS引擎预编译期间进行提升
// 那么为什么函数表达式却不会呢?
var fn = function(){};

// 因为在GO的预编译期间,首先寻找变量声明,var fn就是变量声明,而var fn = function(){};虽然是函数声明的一种方式,但是它的执行顺序是,先创建一个变量fn,然后通过赋值的方式将function fn(){}函数在栈内存中的地址赋值给变量fn;所以function(){}函数是在JS引擎执行脚本语言代码的时候定义的。所以在预编译第二阶段寻找函数声明的时候找不到这个匿名函数。这个匿名函数是在JS引擎执行脚本语言是被定义的,GO是对象不会执行。

// 对象内部匿名函数显然不会提升,而且这两个匿名函数是在GO执行(JS引擎执行脚本语言)的时候定义的,和上面的是同一道理。
var obj = {
	name:function(){},
  sex:function(){},
  age:18
}

// GO和AO是给谁看的?预编译是为了什么?函数一定会变量提升吗?

    GOAO的定义是让JS引擎看的,预编译是为了让JS引擎能够更好的去解析代码。上面的例子,在JS引擎执行脚本语言的时候,才将{}赋值给obj变量,obj变量内部存放是的指向{}的指针,obj的name属性存放着指向function(){}的指针,当这个对象被定义的时候,匿名函数才会被定义。反过来说,如果单纯的提升一个匿名函数,这个匿名函数也没有指向,对于代码整体来说没有任何意义。

// 预编译去寻找变量的目的是:这次执行先要确定有哪些变量,然后才好去赋值。

4. GO例题:

console.log(a, b); // function a(){}  undefined
function a(){};
var b = function(){};

// 预编译
GO = {
	b:undefind,
  --> function(){}
  a:function a(){},
}

5.3.5 AO与GO预编译

var b = 1;
function test() {
	var a = 1;
  var b = 2;
  console.log(b); // 2
}
test();

// 预解析
GO = {
	b: undefined,
  --> 1
  test:function test(){},
 
}

AO = {
	a:undefined,
  --> 1,
  b:undefined,
  --> 2,
}
var b = 3;
console.log(a); // function a(a) {}
function a(a) {
	console.log(a); // function a() {}
  var a = 2;
  console.log(a); // 2
  function a() {};
 	var b = 5;
  console.log(b); // 5
}
a(1);

// GO = {
	 b:undefined,
     --> 3,
   a:function a(a) {}
}

// AO = {
	 a:undefined,
     --> 1
     --> function a(){}
     --> 2
   b:undefined,
     --> 5
}
a = 1;
function test() {
	console.log(a); // undefined
  a = 2;
  console.log(a); // 2
  var a = 3;
  console.log(a); // 3
}
test();
var a;

// GO = {
		a:undefined,
      --> 1
  	test:function() {},
}

// 因为AO环境中预解析时有a变量,所以就不去GO找了
// AO = {
		a:undefined,
  	--> 2
    --> 3
}

\

// 预编译不看语句判断,只看有没有变量声明和函数声明
function test() {
	console.log(b); // undefined
  if(a) {
  	var b = 2;
  }
  c = 3;
  console.log(c); // 3
}
var a;
test();
a = 1;
console.log(a); // 1

// GO = {
	 a:undefined,
     --> 1
   test:function test(){},
   c:undefined,
     --> 3
}

// AO = {
	 b:undefined,
   	--> 2
}
function test() {
  return a;
  a = 1;
  function a() {}
  var a = 2;
}
console.log(test()); // function a() {}

// AO = {
	 a:undefined,
    --> function a() {}
    // 执行
    --> return function a(){}
}
// 函数在没有声明返回值return的情况下,系统会在函数底部自动添加return undefined,终止函数执行。
function test() {
	a = 1;
  function a() {}
  	var a = 2;
    return a;
}
console.log(test()); // 2

//AO = {
	a:undefined,
    --> function a(){}
    --> 1
    --> 2
    --> return a
}
a = 1;
function test(e) {
	function e() {}
  arguments[0] = 2;
  console.log(e); // 2
  if(a) {
  	var b = 3;
  }
  var c;
  a = 4;
  var a;
  console.log(b);  // undefined
  f = 5;
  console.log(c); // undefined
  console.log(a); // 4
}
var a;
test(1);
console.log(a); // 1
console.log(f); // 5

// GO = {
	 a:undefined,
     --> 1
   test:function test(e) {}
	 f:undefined,
     --> 5
}

// AO = {
	 e:undefined,
     --> 1
     --> function e() {}
     --> 2
   a:undefined,
     --> 4
   b:undefined,
     --> undefined
   c:undefined,
}