递归-深浅拷贝-严格模式

本文探讨了递归的概念及其在阶乘和斐波那契数列计算中的应用,强调了递归必须具备的递归条件和出口。同时,介绍了JavaScript中的深浅拷贝,对比了两者的区别,并展示了如何通过递归实现深拷贝以避免重复计算,优化性能。最后,提到了JS严格模式的作用,用于修复ES5之前的缺陷。
摘要由CSDN通过智能技术生成

递归

定义: 程序调用自身的编程技巧称为递归(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";
       
    }
    

mdn 严格模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值