参数默认值/递归/预编译/暗示全局变量

71 阅读4分钟

📌 函数参数默认值

初始化参数 默认值:undefined

  • ES6支持形参赋默认值写法
// ES6 支持直接在形参赋默认值

function test(a = 1, b ){
	console.log(a);
	console.log(b)
}	
test(undefined,2)  // 打印结果:1 2

-----------------------------------------
  
function test(a = undefined, b ){
	console.log(a);
	console.log(b)
}	
test(1,2)  // 打印结果:1 2

形参不设默认值即undefined,通过实参赋值 实参undefined,会使用形参设置的默认值

  • ES5默认值写法
// ES5 设置初始化值方法-----------------------------
//短路运算写法
function test(a, b){
	var a = arguments[0] || 'a设默认值',
      b = arguments[1] || 'b设默认值';
  console.log(a, b)
}
test();

//使用typeof() 方法------------------------------
function test(a, b){
	var a = typeof(arguments[0]) == 'undefined' ? 'a设默认值' : arguments[0],
      b = typeof(arguments[1]) == 'undefined' ? 'a设默认值' : arguments[1];
	console.log(a, b)
}
test();

📌 递归函数

递归函数实现形式

递归函数就是在函数体内部调用自己,使用时要注意函数终止条件,避免死循环

递归两个必要因素:递归方程,递归结束条件

function getSum(x) {
    if (x==1) return 1
    return x + getSum(x - 1);
};
getSum(5)


getSum(5) = 5 + getSum(5 - 1)
getSum(4) = 4 + getSum(4 - 1)
getSum(3) = 3 + getSum(3 - 1)
getSum(2) = 2 + getSum(2 - 1)
getSum(1) = 1 ——>当x == 1时,通过if条件直接返回数值1

//解析
getSum(5) = (5 + (4 + (3 + (2 + getSum(1)))) 
getSum(5) = 5 + (4 + (3 + (2 + 1)))
结果:15

递归技巧

  • 假设递归函数已经写好
  • 寻找递推关系
  • 将递推关系的结构转换为递归体
  • 将临界条件加入到递归体中

**小试牛刀——**递归函数实现深拷贝

// 使用递归方式,实现深拷贝

//【深拷贝】:将数据的所有引用结构都拷贝一份, 数据在内存中独立
//【浅拷贝】:只针对当前对象的属性进行拷贝, 属性引用类型不考虑

1.假设已经实现 clone ( o1, o2),将对象 o2 的成员拷贝一份交给 o1
2.寻找递推关系
function clone( o1, o2){
    for(var key in o2){
        o1[key] = o2[key]; //需要考虑o2[key]时引用类型,再次使用clone函数,否则直接赋值
    }
}
3.临界条件: 因为时for in 循环,没有成员遍历,自动结束
4.递归函数
 function clone(o1,o2){
     for(var key in o2){
         if(typeof o2[key] == 'object'){
             o1[key] = {};
             clone(o1[key],o2[key])
         }else{
             o1[key] = o2[key];
         }
     }
 }

📌 预编译

JavaScript运行三部曲

  • 语法分析:通篇检查低级语法错误,不执行
  • 预编译:内存中开辟空间,存放一些变量与函数
  • 解释执行:解释一行,执行一行

JavaScript预编译分析

预编译不仅仅发生在script内代码块执行前,大部分会发生在函数执行前

  • 页面产生便创建了GO全局对象【Global Object】—— window对象
  • 第一个脚本文件加载至完成
  • 通篇分析语法是否合法
  • 开始进行预编译GO【脚本代码块script执行前】

1、查找全局变量声明(包括隐式全局变量声明),变量名作为全局对象GO属性,值赋予undefined

2、查找function函数声明,函数名作为全局对象GO属性,值赋予函数体

  • 函数调用AO【函数执行前】

1、创建AO对象【Active Object】

2、查找函数形参即函数内变量声明,形参名即变量名作为AO对象属性,值为undefined

3、实参形参相统一,实参值赋给形参

4、查找函数声明,函数名作为AO对象属性,值赋予函数体

📌 暗示全局变量

暗示全局变量基于JavaScript 的两个特性

  • 可直接使用变量,甚至无需声明
  • 任何变量,如果未经声明,就为全局对象所有
var a = 1; //函数体外声明的变量称为全局变量
b = 2; // 无论函数体外或函数体内未声明的变量都称为暗示全局变量
function fn() {
    var c = 3; //函数体内声明的变量称为局部变量
    d = 4; // 暗示全局变量
}
fn(); // 若不执行函数,则不会进行函数预编译,d 就不会提升为全局变量
console.log(c); // error: c is not defined
console.log(d); // 4

暗示全局变量与明确定义全局变量的不同之处?

  • 使用var声明创建的全局变量,不能删除
  • 暗示全局变量,可以删除

暗示全局变量非变量:****严格来讲暗示全局变量不是真正的变量,而是全局对象属性,属性可以通过delete操作符删除,但变量不可以

 1 var global_var = 1;
 2     global_novar = 2;
 3     (function(){
 4     	  global_fromfunc = 3;
 5     });
 6 
 7 //企图删除
 8 delete global_var;					//false
 9 delete global_novar;				//true
10 delete global_fromfunc;		//true
11 
12 typeof global_var;				//"number"
13 typeof global_novar;			//"undefined"
14 typeof global_fromfunc;	//"undefined"