📌 函数参数默认值
初始化参数 默认值:undefined
- ES6支持形参赋默认值写法 ```javascript // 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,会使用形参设置的默认值 **<br />**- **ES5默认值写法**```javascript// 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 1return 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 的成员拷贝一份交给 o12.寻找递推关系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 definedconsole.log(d); // 4
暗示全局变量与明确定义全局变量的不同之处?**
- 使用var声明创建的全局变量,不能删除
- 暗示全局变量,可以删除
暗示全局变量非变量:严格来讲暗示全局变量不是真正的变量,而是全局对象属性,属性可以通过delete操作符删除,但变量不可以
1 var global_var = 1;2 global_novar = 2;3 (function(){4 global_fromfunc = 3;5 });67 //企图删除8 delete global_var; //false9 delete global_novar; //true10 delete global_fromfunc; //true1112 typeof global_var; //"number"13 typeof global_novar; //"undefined"14 typeof global_fromfunc; //"undefined"
📋 课后作业
分析下列代码预编译过程
【题一】------------------------------------------------------------------function test() {return a;a = 1;function a() { }var a = 2;}console.log(test());【分析过程】:GO:{test:function test(){.....}test-AO:{a: undefined ——> function a(){}}}【结果】:"function a(){}"return后面的a的赋值操作不执行【题二】--------------------------------------------------------------------function test() {a = 1;function a() { }var a = 2;return a;}console.log(test());【分析过程】:GO:{test:function test(){...}test-AO:{a: undefined ——> function a(){} ——> 1 ——> 2}}【结果】:21-执行test()函数会在GO中创建test的AO局部作用域,开始进行预解析2-首先将var声明的a变量提升当前AO顶部,赋值undefined3-其次将声明的a函数作为值,赋给已声明的a变量,开始执行当前AO代码4-自上而下,首相将1赋值给变量a,其次又将2赋值给变量25-最终a变量的值为2,return变量a的值为2【题三】--------------------------------------------------------------------------a = 1;function test(e) {function e() {}arguments[0] = 2;console.log(e);if (a) {var b = 3;}var c;a = 4;var a;console.log(b);f = 5;console.log(c);console.log(a);}var a;test(1)console.log(a);console.log(f);【分析过程】:GO:{a:undefined ——> 1f: 5test: function test(e) {...}test-AO:{b: undefinedc: undefineda: undefined ——> 4e: undefined ——> 1 ——> function e() {} ——> 2}}【结果】:2undefinedundefined415
