JavaScript对象浅拷贝与深拷贝原理及实现
本文详细解析JavaScript中对象的浅拷贝与深拷贝机制。通过手动实现extendCopy和deepCopy函数,阐明基本类型与引用类型在内存地址上的区别。同时介绍jQuery中$.extend()方法的递归合并功能及其在插件开发中的应用,并探讨JS中对象相等的判断逻辑。
JavaScript对象浅拷贝与深拷贝原理及实现
本文分享了JavaScript中对象浅拷贝和深拷贝的具体实现代码,供读者参考。
浅拷贝机制与缺陷
1. 浅拷贝
拷贝操作的核心是将父对象的属性全部复制到子对象中。
以下函数展示了如何实现这一拷贝过程:
var Chinese = {
nation:'中国'
}
var Doctor = {
career:'医生'
}
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
使用时,代码如下:
var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国
然而,这种拷贝方式存在一个缺陷:如果父对象的属性值是数组或另一个对象,子对象获得的仅仅是该属性的内存地址,而非真正的数据副本。因此,修改子对象中的引用类型属性可能会意外篡改父对象的数据。
例如,现在给Chinese对象添加一个名为“出生地”的属性,其值为一个数组。
Chinese.birthPlaces = ['北京','上海','香港'];
接着,通过extendCopy()函数让Doctor继承Chinese。
var Doctor = extendCopy(Chinese);
随后,向Doctor的“出生地”数组中添加一个城市:
Doctor.birthPlaces.push('厦门');
观察输出结果:
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门 alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门
结果显示,Doctor和Chinese的出生地列表都被修改了。
由此可见,extendCopy()仅对基本类型数据进行了值拷贝,这种拷贝方式被称为“浅拷贝”。
深拷贝的实现方法
2. 深拷贝
鉴于浅拷贝存在上述弊端,接下来介绍深拷贝的实现方式。
深拷贝旨在实现真正意义上的数组和对象副本。其实现并不复杂,只需对浅拷贝逻辑进行递归调用即可。
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
使用方法如下:
var Doctor = deepCopy(Chinese);
现在,给父对象添加一个属性,其值为数组,并在子对象上修改该属性:
Chinese.birthPlaces = ['北京','上海','香港'];
Doctor.birthPlaces.push('厦门');
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港
这样便完成了深拷贝操作。
jQuery $.extend()方法详解
$.extend()方法
jQuery库中的$.extend()方法也具备类似功能。
$.extend( [deep ], target, object1 [, objectN ] )
•deep 类型: Boolean 如果是true,合并成为递归(又叫做深拷贝)。 •target 类型: Object 对象扩展。这将接收新的属性。 •object1 类型: Object 一个对象,它包含额外的属性合并到第一个参数. •objectN 类型: Object 包含额外的属性合并到第一个参数
当向$.extend()传递两个或多个对象时,所有对象的属性都会被添加到目标对象(即target参数)中。
如果仅向$.extend()传递一个参数,则意味着省略了目标参数。此时,jQuery对象本身被视为目标对象。这种用法常用于在jQuery命名空间下添加新功能,对于希望向jQuery扩展函数的插件开发者而言非常有用。
需要注意的是,目标对象(第一个参数)会被修改,并通过$.extend()返回。如果希望保留原对象不变,可以将一个空对象作为目标参数传入:
var object = $.extend({}, object1, object2);
默认情况下,$.extend()的合并操作不是递归的。如果第一个对象的某个属性本身是对象或数组,它将被第二个对象中具有相同key的属性完全覆盖,其内部值不会被合并。通过检查示例中banana的值即可理解这一点。然而,若将true作为函数的第一个参数,则会在对象层级进行递归合并。
警告:不支持第一个参数传递 false 。
1. 合并两个对象,并修改第一个对象。
var object1 = {
apple: 0,
banana: { weight: 52, price: 100 },
cherry: 97
};
var object2 = {
banana: { price: 200 },
durian: 100
};
// Merge object2 into object1
$.extend( object1, object2 );
// Assuming JSON.stringify - not available in IE<8
console.log( JSON.stringify( object1 ) );
//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
2. 采用递归方式合并两个对象,并修改第一个对象。
var object1 = {
apple: 0,
banana: { weight: 52, price: 100 },
cherry: 97
};
var object2 = {
banana: { price: 200 },
durian: 100
};
// Merge object2 into object1, recursively
$.extend( true, object1, object2 );
// Assuming JSON.stringify - not available in IE<8
console.log( JSON.stringify( object1 ) );
//{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
3. 合并 defaults 和 options 对象,并且不修改 defaults 对象。这是常用的插件开发模式。
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
// Merge defaults and options, without modifying defaults
var settings = $.extend( {}, defaults, options );
console.log(JSON.stringify( defaults ));
console.log(JSON.stringify( options ));
console.log(JSON.stringify( settings ));
//defaults -- {"validate":false,"limit":5,"name":"foo"}
//options -- {"validate":true,"name":"bar"}
//settings -- {"validate":true,"limit":5,"name":"bar"}
JavaScript对象相等性判断
Javascript 判断对象是否相等
在JavaScript中,相等运算包括“==”和“===”(全等),两者的区别显而易见。本文将探讨如何判断两个对象是否相等。直觉上,如果两个对象拥有相同的属性且属性值也相同,它们可能被视为相等。但通过以下实例可以验证这一观点:
var obj1 = {
name: "Benjamin",
sex : "male"
}
var obj2 = {
name: "Benjamin",
sex : "male"
}
//Outputs: false
console.log(obj1 == obj2);
//Outputs: false
console.log(obj1 === obj2);
从上述例子可见,无论使用“==”还是“===”,结果均返回false。根本原因在于,基本类型(如string、number)通过值进行比较,而对象(包括Date、Array及普通对象)则通过比较指向内存中的地址来判断。参考以下示例:
var obj1 = {
name: "Benjamin",
sex : "male"
};
var obj2 = {
name: "Benjamin",
sex : "male"
};
var obj3 = obj1;
//Outputs: true
console.log(obj1 == obj3);
//Outputs: true
console.log(obj1 === obj3);
//Outputs: false
console.log(obj2 == obj3);
//Outputs: false
console.log(obj2 === obj3);
上例返回true,是因为obj1和obj3的指针指向了内存中的同一地址。这与Java/C++等面向对象语言中值传递和引用传递的概念相似。因此,在判断两个对象是否相等时,必须明确你是希望比较对象的属性结构,还是属性对应的值,抑或是其他逻辑。
function person(name) {
this.name=name;
}
var p1 = new person("p1");
var p2 = new person("p2");
console.log(p1 == p2); //false
person.prototype.sayHi = function() {
// do sayHi here
}
console.log(p1.sayHi() == p2.sayHi()); //true
console.log(p1.sayHi() === p2.sayHi()); //true
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58
