JavaScript数组操作

1.生成数组:

1.1 通过Set中转,生成新的数组

// 将数据添加到Set
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

// 将Set转换成数组
const array = Array.from(s);

 2.数组的拷贝 

2.1 Shallow Copy: 浅拷贝

顶层属性遍历

浅拷贝是指复制对象的时候,指对第一层键值对进行独立的复制。一个简单的实现如下:

// 浅拷贝实现
function shadowCopy(target, source){ 
    if( !source || typeof source !== 'object'){
        return;
    }
    // 这个方法有点小trick,target一定得事先定义好,不然就不能改变实参了。
       // 具体原因解释可以看参考资料中 JS是值传递还是引用传递
    if( !target || typeof target !== 'object'){
        return;
    }  
    // 这边最好区别一下对象和数组的复制
    for(var key in source){
        if(source.hasOwnProperty(key)){
            target[key] = source[key];
        }
    }
}

//测试例子
var arr = [1,2,3];
var arr2 = [];
shadowCopy(arr2, arr);
console.log(arr2);
//[1,2,3]

var today = {
    weather: 'Sunny',
    date: {
        week: 'Wed'
    } 
}

var tomorrow = {};
shadowCopy(tomorrow, today);
console.log(tomorrow);
// Object {weather: "Sunny", date: Object}

Object.assign

Object.assign() 方法可以把任意多个的源对象所拥有的自身可枚举属性拷贝给目标对象,然后返回目标对象。Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象身上。注意,对于访问器属性,该方法会执行那个访问器属性的 getter 函数,然后把得到的值拷贝给目标对象,如果你想拷贝访问器属性本身,请使用 Object.getOwnPropertyDescriptor() Object.defineProperties() 方法。

注意,字符串类型和 symbol 类型的属性都会被拷贝。

注意,在属性拷贝过程中可能会产生异常,比如目标对象的某个只读属性和源对象的某个属性同名,这时该方法会抛出一个 TypeError 异常,拷贝过程中断,已经拷贝成功的属性不会受到影响,还未拷贝的属性将不会再被拷贝。

注意, Object.assign 会跳过那些值为 null  undefined 的源对象。

Object.assign(target, ...sources)

使用 [].concat 来复制数组

同样类似于对于对象的复制,我们建议使用[].concat来进行数组的深复制:

1 var list = [1, 2, 3];
2 var changedList = [].concat(list);
3 changedList[1] = 2;
4 list === changedList; // false

同样的,concat方法也只能保证一层深复制:

1 > list = [[1,2,3]]
2 [ [ 1, 2, 3 ] ]
3 > new_list = [].concat(list)
4 [ [ 1, 2, 3 ] ]
5 > new_list[0][0] = 4
6 4
7 > list
8 [ [ 4, 2, 3 ] ]

2.1 DeepCopy: 深拷贝

递归属性遍历

一般来说,在JavaScript中考虑复合类型的深层复制的时候,往往就是指对于Date、Object与Array这三个复合类型的处理。我们能想到的最常用的方法就是先创建一个空的新对象,然后递归遍历旧对象,直到发现基础类型的子节点才赋予到新对象对应的位置。不过这种方法会存在一个问题,就是JavaScript中存在着神奇的原型机制,并且这个原型会在遍历的时候出现,然后原型不应该被赋予给新对象。那么在遍历的过程中,我们应该考虑使用hasOenProperty方法来过滤掉那些继承自原型链上的属性:

 1 function clone(obj) {
 2     var copy;
 3 
 4     // Handle the 3 simple types, and null or undefined
 5     if (null == obj || "object" != typeof obj) return obj;
 6 
 7     // Handle Date
 8     if (obj instanceof Date) {
 9         copy = new Date();
10         copy.setTime(obj.getTime());
11         return copy;
12     }
13 
14     // Handle Array
15     if (obj instanceof Array) {
16         copy = [];
17         for (var i = 0, len = obj.length; i < len; i++) {
18             copy[i] = clone(obj[i]);
19         }
20         return copy;
21     }
22 
23     // Handle Object
24     if (obj instanceof Object) {
25         copy = {};
26         for (var attr in obj) {
27             if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
28         }
29         return copy;
30     }
31 
32     throw new Error("Unable to copy obj! Its type isn't supported.");

调用如下:

 1 // This would be cloneable:
 2 var tree = {
 3     "left"  : { "left" : null, "right" : null, "data" : 3 },
 4     "right" : null,
 5     "data"  : 8
 6 };
 7 
 8 // This would kind-of work, but you would get 2 copies of the 
 9 // inner node instead of 2 references to the same copy
10 var directedAcylicGraph = {
11     "left"  : { "left" : null, "right" : null, "data" : 3 },
12     "data"  : 8
13 };
14 directedAcyclicGraph["right"] = directedAcyclicGraph["left"];
15 
16 // Cloning this would cause a stack overflow due to infinite recursion:
17 var cylicGraph = {
18     "left"  : { "left" : null, "right" : null, "data" : 3 },
19     "data"  : 8
20 };
21 cylicGraph["right"] = cylicGraph;

利用 JSON 深拷贝

JSON.parse(JSON.stringify(obj));

对于一般的需求是可以满足的,但是它有缺点。下例中,可以看到JSON复制会忽略掉值为undefined以及函数表达式。

 1 var obj = {
 2     a: 1,
 3     b: 2,
 4     c: undefined,
 5     sum: function() { return a + b; }
 6 };
 7 
 8 var obj2 = JSON.parse(JSON.stringify(obj));
 9 console.log(obj2);
10 //Object {a: 1, b: 2}
原文地址:https://www.cnblogs.com/hwubin5/p/8413904.html