零基础快速掌握JavaScript数组深拷贝与浅拷贝

Posted 志在四方csj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了零基础快速掌握JavaScript数组深拷贝与浅拷贝相关的知识,希望对你有一定的参考价值。

目录

一.数组基础

1.创建数组

1.使用Array构造函数创建

2.使用字面量方法创建

3.应用:创建一个包含1-100的数组

 2.数组遍历

遍历的两种方式f(for、for-in循环)

二.数组实现深拷贝、浅拷贝

1.深拷贝与浅拷贝

2.数组的深拷贝与浅拷贝

三.可迭代对象或类数组转化为真数组

1.可迭代对象与类数组的区别

可迭代对象(Iterable)

类数组(Array-like)

2.可迭代对象或类数组转化为真数组

Array.from()方法进行转换(ES6)

使用遍历方式(for-in)把成员放到一个新数组中 

四.数组检测

instanceof操作符

Array.isArray()方法

五.数组的序列化与反序列化

六.数组的原型方法

1.构造函数的方法

2.原型的方法

栈与队列的方法(改变原数组)

排序方法

操作方法

位置方法

迭代方法


一.数组基础

ECMAScript数组是有序列表,是存放多个值的集合。

有以下特性:

每一项都可以保存任何类型的数据。(字符串、数值、数组)数组一般都放置同一类型的数据

数组的大小是可以动态调整。

数组length属性:可读可写,可以通过设置length的值从数组的末尾移除项或向数组中添加新项

js中的数组是可以存放任意数据类型值的集合,数组的元素可以是任意数据类型,数组的长度可以动态调整。

1.创建数组

1.使用Array构造函数创建

//数组创建
//使用Array构造函数创建
var arr1 = new Array(5);//()内数字表示在创建时初始化数组长度
arr1[0] = 'zhangshan';
arr1[1] = 'lisi';
arr1[2] = 'wangwu';
console.log(arr1);//[ 'zhangshan', 'lisi', 'wangwu', <2 empty items>(两项为空值) ]
console.log(arr1.length);//5

2.使用字面量方法创建

//字面量创建  数组是[]  对象是{}
var arr2=['zhangshan','lisi','wangwu'];
console.log(arr2);//[ 'zhangshan', 'lisi', 'wangwu' ]

3.应用:创建一个包含1-100的数组

push()方法是数组的栈底添加 意思是往数组的底部添加
unshift()方法是数组的栈顶添加 意思是往数组的头部添加

//创建一个数组包含1-100
//方法一:var nums = [1,2,...]
var nums = [];
for(var i=0;i<100;i++){
    nums[i] = i+1;
}
console.log(nums);//1-100

//从小到大输出1-100所有的偶数
var nums = [];
for(var i=0;i<100;i++){
    if(i%2==0){nums.push(i)}
}
console.log(nums);
//从大到小输出1-100所有偶数
var nums = [];
for(var i=0;i<100;i++){
    if(i%2==0){nums.unshift(i)}
}
console.log(nums);
//从小到大输出1-100所有奇数
var nums = [];
for(var i=0;i<100;i++){
    if(i%2!=0){nums.push(i)}
}
console.log(nums);

 2.数组遍历

遍历的两种方式f(for、for-in循环)

//数组遍历(将每一个成员提取一次) 循环提取数组成员
//for 循环
var nums = [1,2,3];
for(var i=0;i<nums.length;i++){
    console.log(nums[i]);//1,2,3
//可以做一些操作 nums[i]='数字:'+nums[i];
}
console.log(nums);//[1,2,3]

//for...in循环
for(var k in nums){
    console.log(nums[k]);
}

二.数组实现深拷贝、浅拷贝

1.深拷贝与浅拷贝

主要针对于引用数据类型参数说的,浅拷贝表示仅拷贝引用地址,深拷贝表示对于对象的克隆

如何实现深拷贝:

1、JSON序列化     :JSON.parse(JSON.stringify(obj))

2、Object.assign()拷贝    :Object.assign({}, obj1);//深拷贝

2.数组的深拷贝与浅拷贝

浅拷贝(数组): (会改变原数组)

就是数组A重新赋值给数组B,数组B里的属性值被改变,则数组A里的值也会跟着发生改变。

深拷贝(数组): (不会改变原数组)

(1)使用slice() 和 concat()方法来实现深拷贝

(2)利用循环实现

//数组也为引用数据类型{}
var arr3 = [1,2,3];
var arr4 = arr3;
arr4[3] = 4;
console.log(arr3);//[ 1, 2, 3, 4 ] 发生浅拷贝

//数组实现深拷贝
var arr5 = [];//创建新数组,把数组3的成员遍历,一个一个加入数组5
for(var k in arr3){
    arr5.push(arr3[k]);
}
var arr6 = arr3.concat(5,6);//数组拼接函数,返回新数组[1,2,3,5,6]
arr6.push(4) //[1,2,3,4,5,6]不影响被拷贝的数组

三.可迭代对象或类数组转化为真数组

1.可迭代对象与类数组的区别

可迭代对象(Iterable

Iterable 对象是数组的泛化。即任何对象都可以被定制为可在 for..of 循环中使用的对象。数组、字符串都是可迭代的。从技术上讲,对象不是数组,而是表示某物的集合(列表,集合),for..of 是一个能够遍历它的很好的语法

Iterable 如上所述,是实现了 Symbol.iterator 方法(用于使对象可迭代的内置 symbol)的对象。

类数组(Array-like

Array-like 是有索引和 length 属性的对象,所以它们看起来很像数组

var obj = {
    0:'zhangsan',
    1:'lisi',
    2:'wangwu',
    length:3
}

可迭代对象和类数组对象通常都 不是数组,它们没有 pushpop 等方法

2.可迭代对象或类数组转化为真数组

Array.from()方法进行转换(ES6)

Array.from 方法接受对象,检查它是一个可迭代对象或类数组对象,然后创建一个新数组,并将该对象的所有元素复制到这个新数组。j然后我们就可以对这个数组进行真数组的操作了

//将可迭代对象或者类数组对象转换为真数组
var obj = {
    '0':'zhangshan',
    '1':'lisi',
    '2':'wangwu',
    'length':3
}
console.log(obj);//{ '0': 'zhangshan', '1': 'lisi', '2': 'wangwu', length: 3 }
var arr_obj = Array.from(obj);
arr_obj.push('zhaoliu');
console.log(arr_obj);//[ 'zhangshan', 'lisi', 'wangwu', 'zhaoliu' ]

使用遍历方式(for-in)把成员放到一个新数组中 

四.数组检测

如何检测一个数据是数组类型

instanceof操作符

Array.isArray()方法

//如何检测一个数据是数组类型
//instanceof 操作符
var arr = [1,2,3];
var obj_arr = {'0':1,'length':1}//类数组
var str = 'hello'//既是类数组也是可迭代对象
console.log(arr instanceof Array); //true
console.log(obj_arr instanceof Array); //false

if(!(obj_arr instanceof Array)){
    obj_arr = Array.from(obj_arr);
}//检测类数组是否为真数组,不是的话就转为真数组
console.log(obj_arr);//【1】


//Array.isArray()  判断一个数据是否是数组
console.log(Array.isArray(arr));//true

console.log(typeof arr);//object 引用数据类型typeof都为object

 五.数组的序列化与反序列化

数组序列化     JSON.stringify()

数组反序列化    JSON.parse()

//数组的序列化和反序列化
var arr = [{id:0,
            name:'zhangshan',
            age:10,
            class:'4-1',
            sex:'nan'},{
                id:1,
                name:'lisi',
                age:10,
                class:'4-1',
                sex:'nan' 
            }];
var arr_str = JSON.stringify(arr);//将数组转为json字符串
console.log(arr_str);//[{"id":0,...,"sex":"nan"},{"id":1,...,"sex":"nan"}]

var new_arr = JSON.parse(arr_str);//将json字符串转回数组
console.log(new_str);//[{ id:0, ...,sex:'nan'},{id: 1, ..., sex: 'nan' }]

 将数据封装为表格

toString() 在默认情况下都会以逗号分隔字符串的形式返回数组项

join() 使用指定的字符串用来分隔数组字符串

split()反序列化,返回一个新数组

//把数据封装成一个表格数据(3*tr>5*td>内容)
var num_arr = [1,2,3];
//通过toSting()将数组转换成字符串,默认以,分割的字符串
var str = num_arr.toString();
console.log(str);//1,2,3
//通过join()将数组通过某个字符拼接转化为字符串
var str2 = num_arr.join('|');//1|2|3
console.log(str2);
//可以通过split()反序列化,返回一个新数组
var new_arr = str.split(',');//字符串方法
console.log(new_arr);//[ '1', '2', '3' ]

六.数组的原型方法

1.构造函数的方法

Array.isArray()     用来判断某个变量是否是一个数组对象

Array.from()         从类数组对象或者可迭代对象中创建一个新的数组实例。

Array.from('foo');   // [ "f", "o", "o" ]
const set = new Set(['foo', 'bar', 'baz', 'foo']);
Array.from(set);    // [ "foo", "bar", "baz" ]

Array.of()/New Array() 根据一组参数来创建新的数组实例,支持任意的参数数量和类型。

Array.of(7);       // [7]
New Array(7);      //7项空值的数组 length=7
Array.of(1, 2, 3); // [1, 2, 3]

2.原型的方法

栈与队列的方法(改变原数组)

栈  LIFO (Last-In-First-Out)  先进的后出

pop() 移除数组中的最后一个项并且返回该项,同时将数组的长度减一,

push()  可接受任意类型的参数,将它们逐个添加到数组的末尾,并返回数组的长度

队列   FIFO (First-In-First-Out)   先进的先出

shift()   移除数组中的第一个项并且返回该项,同时将数组的长度减一

unshift()  在数组的前端添加任意个项,并返回数组的长度

//栈和队列方法,会改变原数组
var arr = [1,2,3];
//arr.push在末尾追加元素
arr.push(4);//[1,2,3,4]
//arr.pop删除最末尾的那个元素
arr.pop();[1,2,3]
//arr.unshift在第一项前面放置元素
arr.unshift(0);[0,1,2,3]
//arr.shift删除第一项元素
arr.shift();[1,2,3]
console.log(arr);

排序方法

排序

 reverse()  反转数组项的顺序,改变原数组

arr.reverse();//3,2,1
console.log(arr);

 sort()

默认排序:该方法会调用每个数组项的toString() 方法,然后按照字符序列排序

自定义排序:

a.该方法可以接受一个比较函数作为参数,比较函数有两个参数

b.如果第一个参数位于第二个参数之前,返回负数

c.如果第一个参数位于第二个参数之后,返回正数

//sort排序,从左起第一位数开始排列,然后向右逐位排序
var num_arr = [1,33,113,223,23,111];//[ 1, 111, 113, 223, 23, 33 ]
console.log(num_arr.sort());
//sort可以完成正常的排序功能,需要传入一个排序的函数
console.log(num_arr.sort(function(v1,v2){
            if(v1>v2)
                return 1;//不换位置
            else if(v1<v2)
                return -1;//换位置
            else
                return 0;
}));//[ 1, 23, 33, 111, 113, 223 ]

排序的算法:冒泡排序、快速排序、插入排序、选择排序

//自己写一个排序函数:冒泡排序
function mysort(arr){
    for(var i=0;i<arr.length-i-1;i++){//排几次
        for(var j=0;j<arr.length-i-1;j++){
            if(arr[j]<arr[j+1]){
                var temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    console.log(arr);
}
mysort([2,3,7,1,4]);

ps:这里有常用的十大排序方法,配有动图生动形象

 操作方法

数组的截取与拼接

截取方法

 concat()  

数组拼接,先创建当前数组的一个副本,然后将接收到的参数添加到这个副本的末尾,返回副本,不改变原数组

//数组的截取与拼接
//concat返回拼接后的新数组
var arr1=[1,2,3];
var arr2=arr1.concat(4,5,6);
console.log(arr2);//[ 1, 2, 3, 4, 5, 6 ]

 slice()  

数组切割,可接受一个或者两个参数(返回项的起始位置,结束位置),当接受一个参数,从该参数指定的位置开始,到当前数组末尾的所有项。当接受两个参数,起始到结束之间的项,但是不包含结束位置的项,即结束索引前。不改变原数组

var arr2 = [ 1, 2, 3, 4, 5, 6 ];
//slice数组切割;返回截取后的新数组
var arr3 = arr2.slice(0,3);//返回结束索引前的部分
console.log(arr3);//[ 1, 2, 3 ]

 splice()  

向数组的中部插入数据将始终返回一个数组,该数组中包含从原始数组中删除的项。

删除:指定两个参数(起始位置,要删除的项数)

插入:指定三个参数(起始位置,0,要插入的任意数量的项)

替换:指定三个参数(起始位置,要删除的项数,要插入的任意数量的项)

var arr2 = [ 1, 2, 3, 4, 5, 6 ];

//splice():接收3个参数(start_index,length,替换或追加的元素)。
//会直接改变原数组,返回选中的元素,可以替换、增加、删除
arr2.splice(2,3,8,8,8);//从下标为2的数值开始替换3个元素,替换为8,8,8
console.log(arr2);// [1, 2, 8, 8, 8, 6 ]

var res=arr2.splice(0,2,66,66);//新建一个数组res存放arr2中被替换掉的元素
console.log(arr2);//[ 66, 66, 8, 8, 8, 6 ]
console.log(res);//[ 1, 2 ]

arr2.splice(2,3,8);//从下标为2的元素开始提取3个元素,但只加了一个8,相当于删除
console.log(arr2);//[ 66, 66, 8, 6 ]

arr2.splice(0,0,8);//未提取,加了一个,相对于追加
console.log(arr2);//[ 8, 66, 66, 8, 6 ]

位置方法

索引方法

 indexOf()  

从数组开头向后查找,使用全等操作符,找不到该元素返回-1。第一个参数为要查找的项,第二个参数(可选)为索引开始位置

 lastIndexOf()  

从数组末尾向前查找,使用全等操作符,找不到该元素返回-1。第一个参数为要查找的项,第二个参数(可选)为索引开始位置

//位置方法 
//indexOf比较适合判断一个数组中是否有某个成员
var arr = [1,2,3,4,5,4,3,2,1];
console.log(arr.indexOf(1));//0 从头开始查找指定元素,找到就退出
console.log(arr.lastIndexOf(1));//8 从末尾开始查找
console.log(arr.indexOf(6));//找不到 -1

//如何将一个数组去重
function qc(arr){//把函数封装
var new_arr=[];
for(var k in arr){
    if(new_arr.indexOf(arr[k])==-1)//如果没有就放入新数组
    new_arr.push(arr[k]);
}
// return new_arr
console.log(new_arr);
}

 迭代方法

      every:对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true

//数组的迭代方法
//every 全部成员都满足,才会返回true (判断一组学生是否满足18岁)
var ages = [19,20,21,18,17,19,20];
var res=ages.every(function(v,index,arr){
    return v>=18;//返回布尔类型的值
})
console.log(res);//false

      some:对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true

//some 只有一个成员满足,就会返回ture (判断一组学生是否含有满足18岁)
var ages1=[19,3,5,7];
var res=ages1.some(function(v,index,arr){
    return v>=18;//返回布尔类型的值
})
console.log(res);//ture

       filter: 对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组

//filter 过滤器 获取一些符合条件的成员(在一群学生中获取满足18岁的)
var ages1=[19,3,5,19,334,3,7];
var res=ages1.filter(function(v,index,arr){
    return v>=18;//返回布尔类型的值
})
console.log(res);//19,19,334

map:对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组

//map方法,遍历方法,有返回值 (过了一年,将所有学生的年龄加一)
var res=ages1.map(function(v,index,arr){
    return v+1;//操作完毕的结果
})
console.log(res);//[20, 4, 6, 20, 335, 4, 8]

           forEach:对数组中的每一项运行给定函数,该方法没有返回值

//foreach方法,无返回值 遍历一次数组成员,做一些操作,没有返回值
var new_arr=[];
ages1.forEach(function(v,index,arr){
    new_arr.push(v+1);
})
console.log(new_arr);//[20, 4, 6, 20, 335, 4, 8]

以上是关于零基础快速掌握JavaScript数组深拷贝与浅拷贝的主要内容,如果未能解决你的问题,请参考以下文章

深拷贝与浅拷贝js,方法

js运用递归实现浅拷和深拷贝

深拷贝与浅拷贝

JavaScript深拷贝与浅拷贝

深拷贝与浅拷贝

深拷贝与浅拷贝