codes 中的最后一个“深度克隆”需要知道如何封装。
Syntax
...数组; // => 对 数组 展开 ES6...对象; // => 对 对象 展开 ES7
展开运算符和剩余参数
虽然两者在写法上一模一样,但是含义却大不相同。区分它们也很简单:
- 写在定义一个函数的形参位置上:表示的是剩余参数。
- 否则:表示的是展开运算符。
codes
- 1.js
/*需求:未知数组求和*//*** 根据指定的长度来创建一个随机数组* @param {Number} len 随机数组的长度*/function createRandomArr(len) {const resultArr = [];for (let i = 0; i < len; i++) {const item = getRandom(1, 10);resultArr.push(item);}return resultArr;}function getRandom(min, max) {return Math.round(Math.random() * (max - min) + min);}function sum(...args) {let result = 0;args.forEach(arg => {result += arg;});return result;}const arr = createRandomArr(3);console.log(arr);// 错误调用方式:sum(arr); // 相当于仅传入了一个参数// 正确调用方式:sum.apply(null, arr); // 将参数合并到一个数组中传入sum(...arr); // 将数组展开后传入
- 2.js
/*需求:数组浅度克隆*/const arr1 = [1, 2, 3];const arr2 = [...arr1];arr1 === arr2; // => falsearr1; // => [1, 2, 3]arr2; // => [1, 2, 3]
- 3.js
/*需求:对象浅度克隆*/const obj1 = {name: '成哥',age: 18,love: '邓嫂'}const obj2 = {...obj1}/* 等价于下面这种写法const obj2 = {name: obj1.name,age: obj1.age,love: obj1.love}*/obj1; // => { name: '成哥', age: 18, love: '邓嫂' }obj2; // => { name: '成哥', age: 18, love: '邓嫂' }obj1 === obj2; // => false
- 4.js
/* 重复定义的对象属性对象属性不能重复定义,若重复定义的话,那么之后定义的属性值会覆盖之前的。利用这一特点,可以实现很多需求。比如:对象混合。既能确保源对象不变,又能创建一个新的对象。这种操作在 React 中会很常见。*/const obj1 = {name: '成哥',age: 18,love: '邓嫂'}const obj2 = {...obj1,name: '邓哥'}obj1; // => { name: '成哥', age: 18, love: '邓嫂' }obj2; // => { name: '邓哥', age: 18, love: '邓嫂' }obj1 === obj2; // => false
- 5.js
/* [示例] 在封装插件的时候,一般都会用到对象混合。配置对象中的参数,若默认配置对象中的值与用户传入的值有冲突,那么优先使用用户传入的值。*/// 用户传入的配置对象let options = {width: '100',height: '100'}// 默认的配置对象const defaultOptions = {width: '200',height: '200',color: '#008c8c'}options = {...defaultOptions,...options}options; // => { width: '100', height: '100', color: '#008c8c' }defaultOptions; // => { width: '200', height: '200', color: '#008c8c' }
- 6.js
// 用户传入的配置对象let options = {width: '100',height: '100'}// 默认的配置对象const defaultOptions = {width: '200',height: '200',color: '#008c8c'}options = Object.assign({}, defaultOptions, options);options; // => { width: '100', height: '100', color: '#008c8c' }defaultOptions; // => { width: '200', height: '200', color: '#008c8c' }/*个人对 Object.assign() 的理解Object.assign({}, defaultOptions, options); // 以该语句为例第一个参数是一个 {} 空对象 内存空间的地址假设为 a第二个参数是 defaultOptions对象第三个参数是 options对象Object.assign() 做的事情就是1. 先把第二个对象给展开 然后把它的所有键值对 丢到 a 中2. 再把第三个对象给展开 同样地把它的所有键值对 丢到 a 中3. ...一旦发现了了冲突的键 那么 以后面丢进来的为准最后将 a 返回*/
- 7.js
/*浅度克隆*/const obj1 = {name: '成哥',age: 18,love: '邓嫂',address: {country: '中国',province: '黑龙江',city: '哈尔滨'}}const obj2 = {...obj1}obj1;obj2;obj1.address === obj2.address;/* output{name: '成哥',age: 18,love: '邓嫂',address: { country: '中国', province: '黑龙江', city: '哈尔滨' }}{name: '成哥',age: 18,love: '邓嫂',address: { country: '中国', province: '黑龙江', city: '哈尔滨' }}true*/
- 8.js
/*在我们清楚知道被克隆的对象的结构的前提下,我们可以采用下面这种操作来实现深度克隆。*/const obj1 = {name: '成哥',age: 18,love: ['邓嫂', '成嫂1', '成嫂2'], // love 是一个引用类型address: { // address 也是一个引用类型country: '中国',province: '黑龙江',city: '哈尔滨'}}const obj2 = {...obj1,address: { // 引用类型 进一步展开...obj1.address},love: [...obj1.love, '成嫂3', '成嫂4'] // 引用类型进一步展开 并且 还可以新增一些成员}obj1;obj2;obj1.address === obj2.address;obj1.love === obj2.love;/* output{name: '成哥',age: 18,love: [ '邓嫂', '成嫂1', '成嫂2' ],address: { country: '中国', province: '黑龙江', city: '哈尔滨' }}{name: '成哥',age: 18,love: [ '邓嫂', '成嫂1', '成嫂2', '成嫂3', '成嫂4' ],address: { country: '中国', province: '黑龙江', city: '哈尔滨' }}falsefalse*/
- 深度克隆.js
/* 深度克隆在不清楚对象结构的情况下,可以使用 clone 函数来实现深度克隆。*//*** 克隆* @param {any} target 被克隆的目标* @param {Boolean}} isDeep 是否深度克隆*/function clone(target, isDeep) {// 1. 克隆数组if (Array.isArray(target)) {if (isDeep) {let newArr = [];target.forEach(item => {newArr.push(clone(item, isDeep));});return newArr;} else { // 浅拷贝一个数组return [...target];/* 或者return target.slice();target.slice() 等价于 target.slice(0, target.length); 等价于 [ ...target ] */}}// 2. 克隆对象if (typeof target === 'object') {let newObj = {};if (isDeep) {for (const prop in target) {newObj[prop] = clone(target[prop], isDeep);}} else {for (const prop in target) {newObj[prop] = target[prop];}/* 或者newObj = {...target}*/}return newObj;}// 3. 克隆基本数据类型return target;}
