递归
定义: 程序调用自身的编程技巧称为递归(recursion)。 (即自己调用自己)
递归实现阶乘
1! = 1;
2! = 2*1;
3! = 3*2*1
4!= 4*3*2*1
5! = 5*4*3*2*1
得出数学公式:
fn(1) = 1;
fn(2) = 2 * fn(1)
fn(3) = 3 * fn(2)
fn(4) = 4 * fn(3)
fn(n) = n * fn(n-1)
根据数学公式写出代码::
function factorial(n) {
if (n == 1) return n;
return n * factorial(n - 1)
}
console.log(factorial(5)) // 5 * 4 * 3 * 2 * 1 = 120
递归条件
需要具备两个条件:
- 递归条件。保证可以递归下去。
- 递归出口。结束递归,不结束会引起死循环,程序卡死,导致堆栈溢出
什么时候使用递归?
当子问题须与原始问题为同样的事
,即可使用递归来解决。
斐波那契数列
特点: 前两个数等于后1个数的和;
0 1 1 2 3 5 8
[0,1,1,2,3,5,8]
得出数学公式:
f(下标) = 值
f(0) = 0
f(1) = 1
f(2) = 1 + 0
f(3) = f(2) + f(1)
f(4) = f(3) + f(2)
f(5) = f(4) + f(3)
f(n) =f(n-1) + f(n-2)
代码如下:
function fibonacci(n){
if(n<=1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
上面的缺点:如果递归的下标越大,就会有很多的重复的计算。
如何解决: 利用缓存优化技术。即减少重复计算
衡量一个一个算法的好坏通过复杂度:
-
时间复杂度: 即执行的时间。
console.time(time) for(var i=0; i<10000; i++){ } console.timeEnd(time)
-
空间复杂度: 消耗的内存。
优化版本:
function fibonacci(n){
if(n<=1) return n;
//定义一个数组,缓存每个下标斐波那契数列
let cache = [];
cache[0] = 0;
cache[1] = 1;
for(let i=2; i<=n; i++){
// 当前下标的值是前两个下标的和
cache[i] = cache[i-1] + cache [i-2]
}
// 返回对应下标斐波那契数列
return cache[n];
}
console.time('time')
console.log( fibonacci(30) ); // 8
console.timeEnd('time')
深浅拷贝(克隆)
1、 回顾基本类型和引用类型赋值过程
- 基本类型:按值传递
- 引用类型:按址传递
浅拷贝:浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 , 且新对象跟旧对象共享内存,修改新对象会影响旧对象。
深拷贝:深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象, 且新对象跟旧对象不共享内存,修改新对象不会影响旧对象。
一般可以借助第三方库实现,如 lodash函数工具库的方法
_.clone(value) : 创建一个 value 的浅拷贝(只拷贝第一层)。或 Object.assign() 或 {...obj} 也行
_.cloneDeep(value): 递归拷贝 value。(注:也叫深拷贝)。
总而言之,浅拷贝只复制指向某个对象的内存地址(指针),而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟旧对象不共享内存,修改新对象不会影响旧对象。
实现浅拷贝
-
通过lodash函数库的
_.clone(value)
实现 -
通过
Object.assign()
实现 -
展开运算符
{...obj}
来实现 -
引用类型赋值默认也是浅拷贝
实现深拷贝
- _.clone(value) : 创建一个 value 的浅拷贝(只拷贝第一层)。或 Object.assign() 或 {…obj} 也行
- 通过
JSON.stringify
进行转换,再用JSON.parse
转换回来即可,这样新的对象产生了。但是他有缺点,一些特殊值序列化不了,如undefined、function(){}、symbol
。 - 要通过递归实现
// 实现深拷贝:
// 主函数
function deepCopy(data){
// 只有引用类型才实现深拷贝 []、{}
if(typeof data === 'object'){
if( Array.isArray(data) ){
// 数组
return copyArray(data);
}else {
// 对象
return copyObject(data)
}
}
// 基本类型默认是深拷贝
return data;
}
// 深拷贝数组
function copyArray(arr){
// arr => [a,{},1,[]]
var newArray = []; // 相当于是一个新的内存空间
arr.forEach(item => {
if(typeof item === 'object'){
// 递归调用自己
newArray.push(deepCopy(item))
}else{
newArray.push(item)
}
})
return newArray;
}
// 深拷贝对象
function copyObject(obj){
// obj => {a:1,b:[]}
var newObj = {}; // 相当于是一个新的内存空间
for(let key in obj) {
if(typeof obj[key] === 'object'){ // obj {name:'age'} obj[name] => age
newObj[key] = deepCopy(obj[key])
}else{
newObj[key] = obj[key]
}
}
return newObj;
}
JS严格模式
作用:主要是修补es5之前的一些缺陷。
-
全局开启
<script> "use strict"; </script>
-
函数内开启
function foo(){ "use strict"; }