JS案例:繼承和深複製

繼承:

// 寄生式繼承(聖盃)
			Father.prototype.name = 'Hello' //在Father類中添加一個name屬性

			function Father() {} //構造Father類

			function Son() {} //構造Son類
			var inherit = (function () { //新建一個當即執行函數,(相似雅虎網站的繼承寫法)
				function F() {} //使用閉包產生私有函數
				return function (father, son) { //返回繼承函數
					F.prototype = father.prototype; //私有函數取出父類的原型
					son.prototype = new F(); //實例化私有函數,並將對象賦給子類的原型
					son.prototype.superClass = father; //自定義子類的超類等於父類
					son.prototype.constructor = son; //將子類的構造函數指向本身,不然是父類(由於原型鏈上的constructor是父類)
				}
			}())
			inherit(Father, Son) //調用函數
			Son.prototype.age = 'World' //改變子類的原型(目的:測試父類原型與子類原型是否綁定)
			var son = new Son(); //實例化子類對象
			var father = new Father(); //實例化父類對象
			console.log(son, father)
			console.log(son.name, father.name); //此時父子類都有該屬性。打印(Hello Hello)
			console.log(son.age, father.age) //子類獨有屬性,父類無此屬性。打印(World undefined)

深複製:

簡易版:

var obj = {
				a: 1,
				b: 'hello',
				c: function () {
					console.log(this.a, this.b);
				},
				d: [1, 2, 3, 4, 'a', 'b', false],
				e: {
					a: 11,
					b: '11',
					c: {
						arr: [5, 4, 1, 2, 3],
						obj: {
							z: 'hello',
							y: 'world'
						}
					}
				}
			}
			var obj1 = {}
			obj1 = JSON.parse(JSON.stringify(obj))
			console.log(obj1);

 

進階版:(缺點:遇到不可枚舉項時沒法遍歷,對象中有set和get時只會將結果輸出)

var obj = {
				a: 1,
				b: 'hello',
				c: function () {
					console.log(this.a, this.b);
				},
				d: [1, 2, 3, 4, 'a', 'b', false],
				e: {
					a: 11,
					b: '11',
					c: {
						arr: [5, 4, 1, 2, 3],
						obj: {
							z: 'hello',
							y: 'world'
						}
					}
				},
				f: null,
				g: undefined,
				set count(val) {
					this.f = val;
				},
				get count() {
					return this.f
				}
			}
			var obj1 = {}

			function copyObj(org, tag) { //org是原對象(obj),tag是複製後的對象(obj1)
				var tag = tag || {}; //初始化要複製的對象
				for (var key in org) { //遍歷對象
					if (typeof org[key] === 'object' && org[key] !== null) { //若遍歷的每一項非空且爲對象,則爲引用值,則繼續下一步
						if (org[key].toString() === '[object Object]') {//若引用值.toString等於[object Object],說明該值數據類型爲對象
							tag[key] = {};
						} else {//不然爲數組
							tag[key] = [];
						}
						copyObj(org[key], tag[key])//再次執行函數
					} else { //若每一項除了typeof爲obj之外的值都是原始值,直接賦值便可
						tag[key] = org[key];
					}
				}
				return tag; //遞歸結束後返回對象
			}
			copyObj(obj, obj1)
			obj.e.c.obj.z = 'world';//改變複製後的值觀察複製後的對象是否發生改變
			obj.e.c.obj.y = 'hello';
			console.log(obj, obj1);

 

終極版深複製:(解決進階版的問題)

var obj = {
				a: 1,
				b: 'hello',
				c: function () {
					console.log(this.a, this.b);
				},
				d: [1, 2, 3, 4, 'a', 'b', false],
				e: {
					a: 11,
					b: '11',
					c: {
						arr: [5, 4, 1, 2, 3],
						obj: {
							z: 'hello',
							y: 'world'
						}
					}
				},
				f: null,
				g: undefined,
				set count(val) {
					this.f = val;
				},
				get count() {
					return this.f
				}
			}
			var obj1 = {}

			function copyObj(org, tag) {
				var tag = tag || {}; //初始化要複製的對象
				var name = Object.getOwnPropertyNames(org); //獲取該對象的屬性名,以字符串數組返回
				for (var i = 0; i < name.length; i++) { //遍歷對象
					var desc = Object.getOwnPropertyDescriptor(org, name[i]); //獲取對象的屬性描述對象,無引用關係,返回另外一個對象,改變時原對象不發生變化(複製的關鍵)
					if (typeof desc.value === 'object' && desc.value !== null) { //若遍歷的每一項非空且爲對象,則爲引用值,則進行下一步
						var obj = desc.value.toString() === '[object Object]' ? {} : []; //判斷是數組仍是對象
						Object.defineProperty(tag, name[i], { //設置對象屬性值,前三個的值是返回true或false
							configurable: desc.configurable, //是否可刪除可替換
							enumerable: desc.enumerable, //是否可枚舉可遍歷
							writable: desc.writable, //是否可寫入
							value: obj //對象的值
						});
						copyObj(desc.value, obj); //再次執行函數
					} else {
						Object.defineProperty(tag, name[i], desc); //不然直接將該對象的屬性值進行復制(原始值)
					}
				}
				return tag;
			}
			copyObj(obj, obj1)
			obj.e.c.obj.z = 'world'; //改變複製後的值觀察複製後的對象是否發生改變
			obj.e.c.obj.y = 'hello';
			console.log(obj, obj1);

相關文章
相關標籤/搜索