day09 - JavaScript有关数组和对象的的深拷贝和浅拷贝问题

一、 数据类型

我们知道数据类型分为两类:

基本数据类型:string、number、boolean、null、undefined
存储方式:存储在栈内存中,变量存储的就是值

引用数据类型:Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)
存储方式:存储在堆内存中,变量存储的是地址

具体通过代码来分析:

        //基本数据类型:number 变量存储值,
        //所以此时 b = a 赋值是把 a 的值复制一份给b 
        var a = 2 ;
        var b = a ;
        b++ ;
        console.log(a) ;  // 2

        //引用数据类型:变量存储地址
        //因为arr与arr2共用一个地址,改变arr2也会改变arr
        var arr = [1,2,3] ;
        var arr2 = arr ;
        arr2.push(4) ;
        console.log(arr) ;  //[1,2,3,4] 

可以通过以下图片分析。arr2 = arr 说明这两个引用数据类型指向了同一个堆内存对象。arr赋值给 arr2,实际上他们共同指向了同一个堆内存对象,所以修改 arr2 其实就是修改那个对象,所以通过 arr 也可以访问到,arr也发生了改变
在这里插入图片描述

二、数组的深拷贝和浅拷贝

1.数组的浅拷贝:只复制了地址(共享地址)

// 数组的浅拷贝 --- 只是复制了地址
        var arr = [1,2,3,4,5] ;
        var arr2 = arr ;   //此时arr与arr2公用一个地址

2.数组的深拷贝:复制值
遍历(把原数组中的值存入新的数组) var arr2 = [] ;
slice() 截取数组中的所有值,得到的是一个新数组

方法一:通过遍历复制数组中的值(深拷贝)

// 数组的深拷贝  --- 复制数组中的值
        var arr = [1,2,3,4,5] ;
        var arr3 = [] ;
        //通过遍历复制数组中的值
        arr.forEach(function (v){
            //将arr中的值添加到arr3中
            arr3.push(v) ;
        })
        arr3.push('heolle') ;
        console.log(arr) ;   //[1, 2, 3, 4, 5]
        console.log(arr3) ;   //[1, 2, 3, 4, 5, 'heolle']

方法二:通过slice()截取数组中的值(深拷贝)

// 数组的深拷贝  --- 复制数组中的值
        var arr = [1,2,3,4,5] ;
        var arr3 = arr.slice() ;  
        //或写成  var arr3 = arr.slice(0 , arr.length)
        arr3.push('hello') ;
        console.log(arr3) ; //[1, 2, 3, 4, 5, 'hello']
        console.log(arr) ;  //[1, 2, 3, 4, 5]
        

三、函数的值传递与引用传递

函数传参时:
1.基本数据类型传递的是值

var a = 1 ;
        function fn(n) {
            n++ ;
        }
        fn(a) ;  //基本数据类型只是传递了值过去
        console.log(a) ;  // 1

2.引用数据类型传递的是地址(形参和实参共享地址),因此在封装函数的时候:如果改变原数组,就直接操作形参; 如果不想改变原数组,就实现深拷贝,然后操作新的数

var arr = [1,2,3] ;
        function fn2(arr2){
            arr2.push('a') ;
        }
        fn2(arr) ;  //引用数据类型传递的是地址
        console.log(arr) ;  //[1,2,3,'a']

例子分析:
思路:假设每个存储的地址就是一个房间


        function pop(arr) {  
            // arr = arr3 ;  // arr和arr3存储在608房间
            var newArr = [] ;  // newArr存储在609房间
            for(var i = 0 ; i < arr.length - 1 ; i++) {
                newArr.push(arr[i])
            } 
            // arr = newArr ;  // arr newArr存储在 609
            return newArr
        }
        
        var arr3 = [6,7,4,2,9,1] ;  // 608
        var res = pop(arr3) ;
        console.log(res); //
        console.log(arr3);
        arr3 = res ;


        var arr = [1,2,3] ;  // 存储在608房间
        arr = [6,7,9] ;  // 存储在609房间

四、二维数组

1.二维数组的表示 arr[ i ][ j ] , i 表示第几行、j 表示第几列

        //定义一个二维数组
        var arr = [
            [1, 2, 3],
            [4, 5, 6],
            [2, 3, 4]
        ]
        console.log(arr) ;
        console.log(arr[0][1]) ;   //表示第一行第二个

在这里插入图片描述

2.二维数组遍历

for(var i in arr) {
            for(var j in arr[i]) {
                console.log(arr[i][j]);
            }
        }

利用二维数组封装concat() 实现数组的拼接

//利用二维数组封装concat() 实现数组的拼接
        function concat(){
            //打印出数组中的值
            console.log(arguments) ;
            var newArr = [] ;
            //遍历数组
            for(var i in arguments){
                for(var j in arguments[i]){
                    console.log(arguments[i][j]) ;
                    newArr.push(arguments[i][j]) ;
                }
            }
            console.log(newArr);
        }

        concat([1,2,3] , [4,5,6]) ;

3.多维数组的深拷贝
1.多维数组深拷贝如果我们采用一般的slice截取,这种方法只是复制了数组的第一维,由于数组第一维存放的是第二维的引用,而第二维才是实际存放了他们的内容。这时候我们需要用for循环一个个拷贝一维数组

        function deepArr(arr){
            //定义一个新数组,存储传过来的值
            var newArr = [] ;
            //循环遍历数组的值,此时遍历的是第一维
            for(var i = 0 ; i < arr.length ; i++){
                //判断,如果遇到二维,就回调遍历第二维的值,然后放入newAree
                if(Array.isArray(arr[i])){
                    //继续遍历,还是得到一个数组
                    var list = deepArr(arr[i]) ;
                    //再把得到的数组放入 newArr
                    newArr.push(list) ;
                }
                else{
                    newArr.push(arr[i]) ;
                }
            }
            return newArr ;
        }

        var arr = [1,2,3,4,[5,6],7]
        var res = deepArr(arr) ;
        arr[4].push('hello') ;
        console.log(arr) ;    //[1, 2, 3, 4, [5,6,'hello'], 7]
        console.log(res) ;    //[1, 2, 3, 4, [5,6], 7]
        ///可以观察到当原数组arr发生了改变时,
        //但是newArr没有发生改变,实现了二维数组的深拷贝,
        //多维数组深拷贝原理也是一样的

五、对象

数组:存储同一种类型的数据,具有有序性
对象:描述同一类型的事物(属性,方法),具有无序性

对象拥有属性和方法,在JavaScript中,几乎所有的事物都是对象
属性:属性值
方法:函数

对象的两种访问方式 :
1.person[‘name’] person[‘age’]
2.点语法 person.name person.age

举个简单的例子吧~

//定义一个对象
var person = {
            //属性值
            name : '师爷',
            age : 42 ,
            sex : '男',
            hobby : 'girl' ,
            //方法
            say : function () {  
                console.log('hello world');
            },
            nickname : ''
        }
        console.log(person.name);  // 师爷
        console.log(person['age']) ;   // 42

对象的遍历:

var dog = {
            name : '二哈',
            age : 3 ,
            sex : '公',
            say : function () {  
                console.log('汪');
            }
        }

        //遍历对象
        for(var key in dog){
            console.log(dog[key]) ;
        }

实例化对象 与 对象的赋值

        // 实例化对象  -- 空对象
        var obj = new Object() ;
        // 赋值
        obj.name = '奔驰' ;
        obj.color = 'pink' ;
        obj.price = '100w' ;

对象的深拷贝和浅拷贝:
浅拷贝:拷贝的是地址

var person1 = {
            name : '方总' ,
            age : 18
        }

        //浅拷贝
        var person2 = person1 ;
        person2.name = '师爷' ;
        console.log(person1) ;  //此时person1的name属性也是'师爷'

深拷贝:拷贝的是值

//深拷贝 , 通过遍历赋值
        var person2 = new Object() ;
        for(var key in person1){
            //将person1的值通过遍历赋给person2
            person2[key] = person1[key] ;
        }
        console.log(pesson2) ;  
        person2.age = 20 ;
        console.log(person1) ; 
        //此时person2的age属性变成了20,但是person1的属性还是18
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值