let obj1 = $.extend(); console.log(obj1); // 返回一个空对象 {} let obj2 = $.extend(undefined); console.log(obj2); //返回jQuery对象,Object.assign传入undefined会报错 let obj3 = $.extend('123'); console.log(obj3); // 返回jQuery对象,Object.assign传入'123'会返回字符串的String对象 let target = { a: 123, b: 234 }; let source1 = { b: 456, d: ['keith', 'peaceful', 'lovely'] }; let source2 = {c: 789}; let source3 = {}; let obj4 = $.extend(target, source1, source2); // let obj4 = $.extend(false, target, source1, source2); console.log(obj4); // {a: 123, b: 456, d: Array(3), c: 789} // 默认情况下,复制方式都是浅复制 // 如果只需要浅复制,不传入deep参数也可以 // 浅复制时,obj4对象中的d属性只是指向数组对象的指针 let obj5 = $.extend(target, undefined, source2); let obj6 = $.extend(target, source3, source2); console.log(obj5, obj6); // {a: 123, b: 234, c: 789}, {a: 123, b: 234, c: 789} // 会略过空对象或Undefined、Null值 let obj7 = $.extend(true, target, source1, source2); console.log(obj7); // {a: 123, b: 456, d: Array(3), c: 789} // 这里target对象有b属性,源对象source1也有b属性 // 此时源对象的b属性会覆盖目标对象的b属性 // 这里deep=true,属于深复制 // 当name=d时,会递归调用$.extend, 直到它的属性对应的属性值全部为基本数据类型 // 源对象的改变不会影响到obj7对象
JavaScript 复制对象
因此,可以根据$.extend方法,写出一个通用的实现对象深浅复制的函数,copyObject函数唯一的不同就是当i =https://www.jb51.net/article/== arguments.length属性时,copyObject函数直接返回了target对象
function copyObject () { let i = 1, target = arguments[0] || {}, deep = false, length = arguments.length, name, options, src, copy, copyIsArray, clone; // 如果第一个参数的数据类型是Boolean类型 // target往后取第二个参数 if (typeof target =https://www.jb51.net/article/== 'boolean') { deep = target; // 使用||运算符,排除隐式强制类型转换为false的数据类型 // 如'', 0, undefined, null, false等 // 如果target为以上的值,则设置target = {} target = arguments[1] || {}; i++; } // 如果target不是一个对象或数组或函数 if (typeof target !== 'object' && !(typeof target =https://www.jb51.net/article/== 'function')) { target = {}; } // 如果arguments.length =https://www.jb51.net/article/== 1 或 // typeof arguments[0] =https://www.jb51.net/article/== 'boolean', // 且存在arguments[1],则直接返回target对象 if (i =https://www.jb51.net/article/== length) { return target; } // 循环每个源对象 for (; i < length; i++) { // 如果传入的源对象是null或undefined // 则循环下一个源对象 if (typeof (options = arguments[i]) != null) { // 遍历所有[[emuerable]] =https://www.jb51.net/article/== true的源对象 // 包括Object, Array, String // 如果遇到源对象的数据类型为Boolean, Number // for in循环会被跳过,不执行for in循环 for (name in options) { // src用于判断target对象是否存在name属性 src = target[name]; // copy用于复制 copy = options[name]; // 判断copy是否是数组 copyIsArray = Array.isArray(copy); if (deep && copy && (typeof copy =https://www.jb51.net/article/== 'object' || copyIsArray)) { if (copyIsArray) { copyIsArray = false; // 如果目标对象存在name属性且是一个数组 // 则使用目标对象的name属性,否则重新创建一个数组,用于复制 clone = src && Array.isArray(src) ? src : []; } else { // 如果目标对象存在name属性且是一个对象 // 则使用目标对象的name属性,否则重新创建一个对象,用于复制 clone = src && typeof src =https://www.jb51.net/article/== 'object' ? src : {}; } // 深复制,所以递归调用copyObject函数 // 返回值为target对象,即clone对象 // copy是一个源对象 target[name] = copyObject(deep, clone, copy); } else if (copy !== undefined){ // 浅复制,直接复制到target对象上 target[name] = copy; } } } } // 返回目标对象 return target; }