2021-05-12

闭包

闭包closure

       定义:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数的内部变量,且返回的那个函数在外部被执行,就产生了闭包.闭包是一个环境,具体指的就是外部函数--高阶函数

        闭包的特性:

            ①函数嵌套函数;

            ②内部函数可以直接访问外部函数的内部变量或参数;

            ③变量或参数不会被垃圾回收机制回收。

        闭包的优点:

            ①变量长期驻扎在内存中;

            ②避免全局变量的污染;

            ③私有成员的存在。

       闭包的缺点: 常驻内存,增大内存的使用量,使用不当会造成内存泄漏。

 

  1. 深拷贝和浅拷贝?

浅拷贝:浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。

 

深拷贝:深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

 

深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝;

浅拷贝(只能拷贝一层):Object.assign和for in进行{ }和[ ]的拷贝。

//拷贝1层(测试)

//Object.assign()拷贝方法
    //拷贝{}
        a = {name:"张三"};
        b = Object.assign({},a);
        b.name = "李四";    //拷贝完之后进行改变属性,测试拷贝的属性值改变原数据是否改变。
        console.log(a,b);
        //输出:{name:"张三"} 
               {name:"李四"} (拷贝成功)
    //拷贝[]
        a = ["1","2","3"];
        b = Object.assign([],a);
        b[1]="hello";
        console.log(a,b)
        //输出:["1","2","3"] 
               ["1","hello","3"] (拷贝成功)

//for in拷贝方法
    var copy = function(a){
        var res = a.constructor();
        for(var key in a){
            if(a.hasOwnProperty(key)){
                res[key] = a[key]
            }
        }
        return res;
    }   
    a = {name:"123",people:{name:"456"}};
    b = copy(a);
    b.people.name="hello"; 
    a = ["a","b","c"];b = copy(a);
    b[1] = 0;//拷贝完之后进行改变属性,测试拷贝的属性值改变原数据是否改变。
    console.log(a,b)  
    //输出:["a","b","c"] 
           ["a","0","c"] (拷贝成功)
//拷贝2层(测试)-------------------------------------------------------------
    //Object.assign()拷贝方法
        a = {name:"abc",people:{name:"张三"}};
        b = Object.assign({},a);
        b.people.name="李四"; 
        console.log(a,b)    
        //输出:{name:"abc",people:{name:"李四"}} 
               {name:"abc",people:{name:"李四"}} (拷贝失败)    //for in拷贝方法
         var copy = function(a){
             var res = a.constructor();
             console.log(res);
             for(var key in a){
                 if(a.hasOwnProperty(key)){
                    res[key] = a[key]
                 }
             }
         return res;
        }       
        a = ["a","b",{name:"张三"}];b = copy(a);b[2].name="李四";
        console.log(a,b)   
        //输出:{name:"abc",people:{name:"李四"}} 
               {name:"abc",people:{name:"李四"}} (拷贝失败)

hasOwnProperty( ) 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键);

深拷贝最简单的实现是:JSON.parse ( JSON.stringify ( obj ) ),同时有一定的缺陷:

① 对象的属性值是函数时,无法拷贝

② 原型链上的属性无法拷贝

③ 不能正确的处理Data类型的数据

④ 不能处理RegExp

⑤ 会忽略symbol、undefined

 

b.name = "bbb"

    console.log(a,b);  

    //输出:{name:"aaa",fun:function(){console.log(1)},age:undefined};

           {name:"bbb"} (拷贝失败,只拷贝到了name属性) 

//JSON.parse(JSON.stringify(obj//JSON.parse(JSON.stringify(obj))方法拷贝2层

    var deepCopy = function(a){

        return JSON.parse(JSON.stringify(a));

    }

    var a = {name:"aaa",people:{name:"abc"}};

    var b = deepCopy(a);

    b.people.name = "def";

    console.log(a,b)  

    //输出:{name:"aaa",people:{name:"abc"}}

           {name:"aaa",people:{name:"def"}} (拷贝成功)//JSON.parse(JSON.stringify(obj))方法拷贝3层

    var deepCopy = function(a){

        return JSON.parse(JSON.stringify(a))

    }

    var a = [1,2,{name:"aaa"}];

    var b = deepCopy(a);

    b[2].name = "bbb";

    console.log(a,b);  

    //输出:["1","2",{name:"aaa"}]

           ["1","2",{name:"bbb"}] (拷贝成功)

//JSON.parse(JSON.stringify(obj))拷贝函数的时候

    var deepCopy = function(a){

        return JSON.parse(JSON.stringify(a));

    }

    var a = {name:"aaa",fun:function(){console.log(1)},age:undefined};

    var b = deep(a);

))拷贝原型链上的属性

    function Person(name){

        this.name=name;

    }

    var a = new Person("Bob");

    var b = deep(a);

    console.log(a.constructor == Person);   //true

    console.log(b.constructor == Object);   //true

    //先不说拷贝出的值,光是数据类型已经不同了 (拷贝失败)

    console.log(a,b)   

    //输出:

// Person{name:"Bob"}    {name:"Bob"}

 

注意:

上述方法会忽略值为function以及undefined的字段,而且对data类型的支持也不太友好。

上述方法只能克隆原始对象自身的值,不能克隆他继承的值。

深拷贝(完美拷贝):

① 如果是基本数据类型,直接返回;

② 如果是RegExp或者Data类型,返回对应类型;

③ 如果是复杂数据类型,递归;

④ 考虑循环引用的问题。

 

function deepClone(obj,hash = new WeakMap()){   //递归拷贝

     if(obj instanceof RegExp) return new RegExp(obj);

     if(obj instanceof Date) return new Date(obj);

     if(obj === null || typeof obj !== 'object'){

         //如果不是复杂数据类型,直接返回

        return obj;

     }

     if(hash.has(obj)){

        return hash.get(obj);

     }

     //如果obj是数组,那么 obj.constructor 是 [Function: Array]

     //如果obj是对象,那么 obj.constructor 是 [Function: Object]

    let t = new obj.constructor();

    hash.set(obj,t);

    for(let key in obj){

        //递归

        if(obj.hasOwnProperty(key)){    //是否是自身的属性

            t[key] = deepClone(obj[key],hash);

        }

     }

     return t;

}  

var show = {

    name:"Bob",

    fun:function(){console.log(1)},

    age:null,

    pic:undefined,

}

var show2 = deepClone(show);

show2.name="Mary"

console.log(show,show2)   //拷贝成功,完美拷贝

 

浅拷贝和深拷贝的区别:

浅拷贝只能复制对象或数组的第一层属性,而深拷贝是拷贝多层,每一级的数据都会被拷贝出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值