ES6深浅拷贝/数组的扩展/对象的拓展

数组的扩展

forEach遍历

//第一个参数为函数
    //函数的第一个参数 是遍历的当前元素
    //函数的第二个参数 当前元素的下标
    //函数的第三个元素 数组本身。
//第二个参数为:函数中this指向。
arr.forEach(function(item,index,arr){
	
},obj);

小练习:将数组中的参数写入页面中(重点是看forEach中第二个参数(函数中this指向。)

<body>
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</body>
<script>
    var arr = [
        "千与千寻",
        "肖申克的救赎",
        "谁先爱上他的",
        "哈尔的移动城堡",
        "海上钢琴师"
    ]
    var lis = document.querySelectorAll("li")
    arr.forEach(function (item, index, self) {
       //  console.log("电影名:"+item+",下标为:"+index);
        this[index].innerHTML = item;
    },lis);
</script>

map方法

map 映射含义,用法与forEach基本类似。

可以在函数中定义返回值。返回是一个数组。

var arr = [
    {name:"千与千寻",score:"8.6"},
    {name:"肖申克的救赎",score:"9.6"},
    {name:"谁先爱上他的",score:"8.3"},
    {name:"哈尔的移动城堡",score:"8.9"},
    {name:"海上钢琴师",score:"9.0"}
]
var arr2 = arr.map(function(item){
    return item.score;
     //等价于    return item["score"];
});
console.log(arr2);// 能够得到这里面的每一个值 "8.6", "9.6", "8.3", "8.9", "9.0"

数组 中 map方法与forEach遍历的比较,

<script>
    var array = ["wo", "shi", "zhao"];
    array.forEach(function (item, index, arr) {
       console.log(item + "  " + index);
        //console.log(arr);
    });
    array.map(function (item, index, arr) {
        console.log(item + "  " + index);
        //console.log(arr);
    });
</script>

在这里插入图片描述在这里插入图片描述

Array.form()

Array.form方法可以将类似数组的对象转为真正的数组。比如:DOM获取的伪数组,arguments对象。

<body>
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</body>
 <script>
    let lis = document.querySelectorAll("li");
    console.log( lis);//输出的是li 的一个伪数组
    var arr = Array.from(lis);//转换为真正数组
    console.log( arr);//这时获取到的li是一个真正的数组
    //用typeof检测时发现都为对象 是因为数组也是对象
</script> 

小练习:将arguments的参数(是一个伪数组)排序

<!-- <script>
   //获取arguments的参数是一个伪数组
    function sort() {
        var args = Array.from(arguments);//转换成了一个真正的数组,
        return args.sort();//这样就能使用数组的排序方法sort()
    }
    console.log(sort(6, 3, 5));
</script> -->

这里在对比一下

<!-- <script>
    let likeArr = {
        length: 3,//这个设置要有,否则输出一个空数组
        "0": "hello",
        "1": "word",
        "2": "你好"
    }
    console.log(likeArr);//{0: "hello", 1: "word", 2: "你好", length: 3}
    let arry = Array.from(likeArr);
    console.log(arry);
    //上下这两种输出都是一个真正的数组,结构样式一样
    var arr = ["hello", "word", "你好"];
    console.log(arr);
</script> -->

在这里插入图片描述

Array.of()

Array.of方法将一组值,转换为数组。

<script>
    let arr = Array.of( 3);
    console.log(arr);//这时只有一个参数,就输出数组,数组里只有一个参数

    let arr2 = new Array(3);//传统数组方法当数组里面只有一个参数时,输出的不是这个数组的内容,而是设置这个数组的长度
    console.log(arr2);//输出  length: 3
    //========================================================
    let arr3 = new Array(1,2,3);
    console.log(arr3);//输出数组  [1, 2, 3]
   //Array.of方法
    let arr4 =  Array.of(1,2,3);
    console.log(arr4);//输出数组  [1, 2, 3]
</script>

copyWithin()

将指定位置的内容复制到其他位置(复制会覆盖原有的内容)然后返回当前数组。

<script>
    //target:必需,从该位置进行覆盖
//start:可选,从该位置开始读取数据,默认为0。如果为负数,表示倒数。
//end:可选 到该位置结束读取数据,默认为数组的长度。如果为负数,表示倒数、
  var arr=[0,1,2,3,4]
    // var arr1= arr.copyWithin(1);
    // console.log(arr1);//[0, 0, 1, 2, 3]
  //  var arr2= arr.copyWithin(1,3);
  //  console.log(arr2);//[0, 3, 4, 3, 4]
    // var arr3= arr.copyWithin(1,2,3);
    // console.log(arr3);//[0, 2, 2, 3, 4]
    // var arr4= arr.copyWithin(1,-2,4);
    // console.log(arr4);[0, 3, 2, 3, 4]
    这几种情况不能同时释放观察,因为同时释放原来的数组值就被改变,复制会覆盖原有的内容
</script>

find()和findIndex()

find方法,找到第一个符合条件的数组元素。
arr.find(function(item,indedx,arr){
//条件判断
})
小练习:(下面没有输出-9,因为它不是第一次出现)

<script>
    var arr = [1, 6, -10, -9].find(function (item) {
        return item < 0;
    })
    // ES6箭头函数写法
  //  var arr = [1, 6, -10, -9].find(item => item < 0)
    console.log(arr);//-10
</script>

findIndex,找到第一个符合条件的数组元素的下标。

var arr = [1, 6, -10, -9].findIndex(item => item < 0)
    console.log(arr);//2

keys(),values(),entries()配合for…of循环

这三个方法主要用于数组的遍历。配合for…of循环。

keys():对键名的遍历

values():对键值的遍历

entries():对键值对的遍历。

格式:
//item 指遍历的当前元素
//arr 指遍历的数组
for (const item of arr) {
	console.log(item);
}
var arr = ["a","b"]
for (const item of arr.keys()) {
	console.log(item);
}
// 0 1
for (const item of arr.values()) {
	console.log(item);
}
// a b
for (const item of arr.entries()) {
	console.log(item);
}
//[0,"a"] [1,"b"]

includes()

该方法可以判断数组是否包含指定的值。
格式

//arr:数组
//value:判断该数组中是否包含该值
//target:从数组的指定位置开始查找。
arr.includes(value,target)

返回值:布尔值 true为包含,false 不包含

console.log( [1,2,3].includes(2)); //true
console.log( [1,2,3].includes("2")); //false
console.log([1,2,3].includes(2,1));//true
console.log([1,2,3].includes(2,2));//false

小练习:

var arr = [1,2,3]
var index = arr.indexOf(2);//利用的是indexOf()方法找不到值返回-1
if(index !== -1){
	console.log("该值已包含");
}else{
	console.log("该值不包含");
}
显示该值已包含
var arr = [1,2,3]
var index = arr.indexOf(2);
includes方法与indexOf()方法的区别
  1. indexOf返回的是下标。 includes返回的是布尔值
  2. indexOf用来判断是否包含不够语义化,不够直观。
  3. indexOf 对于NaN是有误判的。
 <script>这样写就没有了误判
    var arr = [1, 2, 3,NaN]
//    var index = arr.indexOf(NaN);//该值不包含(可是明明有)
    var index = arr.includes(NaN);
    if (index) {
        console.log("该值已包含");
    } else {
        console.log("该值不包含");
    }
</script> 

对象的拓展

一、对象的属性和方法简介写法:

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

属性名和属性值一样时,可以只写一个(语法自动补足)

// 方法:es6
const o = {
  method() {
    return "Hello!";
  }
};

// 等同于原来

const o = {
  method: function() {
    return "Hello!";
  }
};

打印对象用简洁表示法需要加大括号

let user = {
  name: 'test'
};

let foo = {
  bar: 'baz'
};

console.log(user, foo)//原来写法
// {name: "test"} {bar: "baz"}
console.log({user, foo})//es6写法
// {user: {name: "test"}, foo: {bar: "baz"}}

在这里插入图片描述
更多es6详细接地气记载访问
https://www.cnblogs.com/marvintang1001/p/11809665.html

1.对象属性的简洁表示法

ES6可以在对象的大括号中,直接写入变量 和函数,作为对象的属性和方法。如果属性名与变量名相同,则可以简写,只写属性名即可。

var name = "赫本"
var obj = {name}//相当于 var obj = {name:name}
console.log(obj.name); //赫本
<script>
    function fn(a, b) {
        return {
            a,
            b
        };
        /*等价于   return {
               a: a,
               b: b
           };*/
    }
    var obj = fn("hello", "word");
    console.log(obj); //{a: "hello", b: "word"}
</script>
方法的简写

在对象中,可以对方法进行简写

<script>
    let obj = {
            fn() {
                console.log("今晚九点,海岛集合。");
            }
        }
        //相等于
        /* let obj = {
             fn: function() {
                 console.log("今晚九点,海岛集合。");
             }
         }*/
    obj.fn();
</script>

简写只适用于普通函数方法,构造函数不能简写。

2.属性名表达式

拆分的功能,如果是对象,则将对象中的所有属性遍历出来,如果是数组,则将所有的元素遍历出来

<!-- <script>
    let a = {
        x: 1,
        y: 2
    }
    let b = {
        ...a
    }
    console.log(b);// {x: 1, y: 2}
</script> -->
<script>
    let arr = [10, 20, 30];
    let c = {
        ...arr
    }
    console.log(c["0"]);//10
</script>

对象的扩展方法

Object.assign()用于对对象的合并

格式
//第一个参数后面的所有参数,合并到第一个参数中。
Object.assign(target,obj1,obj2)
<script>
    第一个参数后面的所有参数,合并到第一个参数中。
    const target = { name: '奥黛丽·赫本' }
    const obj1 = { age: '20' }
    Object.assign(target, obj1);
    console.log(target);//输出一个改变后的对象    {age: "20" name: "奥黛丽·赫本"}
</script>

同名属性

<script>
     let target = { name: '奥黛丽·赫本' }
    let obj1 = {name: '张三' }
    Object.assign(target, obj1);
    console.log(target);//{name: '张三'}
    //遇到同名属性,则后面的参数对象中的属性会将前面的属性覆盖。
 </script>
用在数组上

用在数组上时,会将数组视为对象。

<script>
    //Object.assign() 用在数组上时,会将数组视为对象。
    var arr1 = [10, 20, 30];
   /*等价于 var  arr1 = {"0":"a", "1":"b", "2":30}*/
     var arr2 = ["a", "b"];
    /*等价于    var arr2 = { 0: "a",  1: "b"}*/
    Object.assign(arr1, arr2);
    console.log(arr1);//a,b,30
</script>

在这里插入图片描述

浅拷贝

浅拷贝:完成拷贝后可能存在彼此之间操作互相影响的就是浅拷贝

深拷贝:完成拷贝后彼此之间操作绝不会有互相影响的就是深拷贝

对基本类型变量,浅拷贝是对值的拷贝,(会影响被拷贝的值)没有深拷贝的概念。
对引用类型来说,浅拷贝是对对象地址的拷贝,并没有开辟新的栈,复制的结果是两个对象指向同一个栈的地址,彼此之间的操作会互相影响,

<script>
    //#### 浅拷贝只拷贝复合数据的内存地址。拷贝后的变量仍然指向原本的对象。
    const target = {
        name: "奥黛丽·赫本",
        sex: "女",
        son: {
            name: "卢卡·多蒂",
            age: "40"
        }
    };
    let obj1 = {
        name: "奥黛丽",
        age: "20",
        son: {
            name: "卢卡·多蒂",
            age: "40"
        }
    }
    Object.assign(target, obj1);
    console.log(target);
    /*合并后的对象输出的为 {age: "20"
        name: "奥黛丽"
         sex: "女"
         son: {name: "卢卡·多蒂", age: 39}}
     我们看到加上来的对象替换了原来名字相同的对象    这里age: 就该为40,只不过 这样的演示不了(下面的40是对的)  
         */
    console.log(target.son.age);//40   
    /*  因为这个我们明白,原来的值没有被改变,他们得到的这个对象是这个对象的内存地址,
    改变的也是也是这个对象的内存地址的内容,没有真正的改变这个对象的内容
    */
    obj1.son.age = 39;//作用  改变里面的值
    console.log(target.son.age);//39       值改变了,是对内存地址的改变,不是对堆中数据的改变
</script>

深拷贝

深拷贝则是开辟新的栈,拷贝后的对象与原来的对象是完全隔离,互不影响

assign对象(合并对象)扩展方法就是浅拷贝。也就是说,如果被合并的对象中有一个属性为对象,那么target对象拷贝得到的是这个对象的内存地址。

<script>
    let obj1 = {
        name: 'tom',
        age: 18,
        sex: '男',
        children: {
            name: '张三',
            age: 200
        }
    }
    let obj2 = {
            sleep: '睡觉'
        }
        //  合并对象
        // let res = Object.assign(target, [obj1, obj2, ....]);
    let res = Object.assign({}, obj1)
   // console.log(res);
    console.log(obj1, obj2);
    obj1.name = 'zhangsan';
    console.log(obj1, obj2);
</script>

合并对象 也能够实现对象的拷贝 深拷贝是狭义(只能拷贝一层); 不能实现真正的深拷贝(对象嵌套的形式)

js 的深拷贝 经典的算法 递归算法实现

总要有一个出口

   var obj1 = {
        children: {
            age: 200
        }
    }
    function deepObj(obj) {
        let newObj = {}声明一个变量用来储存拷贝之后的内容
        for (let key in obj) {
            if (obj[key] instanceof Object) {//实例obj在不在Object构造函数中
                newObj[key] = deepObj(obj[key])
            } else {
                newObj[key] = obj[key]
            }
        }
        return newObj
    }

    let res = deepObj(obj1)
    obj1.children.age = 3400;
    console.log(res); //age变为3400
    console.log(obj1); //age仍为200
<script>
    var obj = {   //原数据,包含字符串、对象、函数、数组等不同的类型
        name: "test",
        main: {
            a: 1,
            b: 2
        },
    }
    function copy(obj) {
        let newobj = null;   //声明一个变量用来储存拷贝之后的内容
        //判断数据类型是否是复杂类型,如果是则调用自己,再次循环,如果不是,直接赋值即可,
        //由于null不可以循环但类型又是object,所以这个需要对null进行判断
        if (typeof (obj) == 'object' && obj !== null) {
            //声明一个变量用以储存拷贝出来的值,根据参数的具体数据类型声明不同的类型来储存
            newobj = obj instanceof Array ? [] : {};
            //循环obj 中的每一项,如果里面还有复杂数据类型,则直接利用递归再次调用copy函数
            for (var i in obj) {
                newobj[i] = copy(obj[i])
            }
        } else {
            newobj = obj
        }
        return newobj;    //函数必须有返回值,否则结构为undefined
    }
    var obj2 = copy(obj)
    obj2.name = '修改成功'
    obj2.main.a = 100;
    console.log(obj, obj2)
</script>

这样就完成了深拷贝,拷贝后的对象与原来的对象是完全隔离

浅拷贝的实现方式:
   1、Object.assign()
   2、lodash 里面的 _.clone 
   3...扩展运算符
   4Array.prototype.concat 
   5Array.prototype.slice
​
    深拷贝的实现方式
    1JSON.parse(JSON.stringify())
    2、递归操作
    3、cloneDeep
    4、Jquery.extend() 

深拷贝的实现方式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值