1. 程式人生 > >JavaScript原型,深克隆和淺克隆的區別

JavaScript原型,深克隆和淺克隆的區別

原型物件

        在JavaScript中,我們建立一個函式A(就是宣告一個函式), 那麼瀏覽器就會在記憶體中建立一個物件B,而且每個函式都預設會有一個屬性 prototype 指向了這個物件( 即:prototype的屬性的值是這個物件 )。這個物件B就是函式A的原型物件,簡稱函式的原型。這個原型物件B 預設會有一個屬性 constructor 指向了這個函式A ( 意思就是說:constructor屬性的值是函式A )。

程式碼:

			function Person(){
				
			}
			function Animal(grander,age){
				this.grander = grander;
				this.age = age;
			}
			Person.prototype.plainProp = 'hi';
			Person.prototype.objectProp = {'age':20};
			
			var a = new Person();
			var b = new Person();
			//淺克隆
			var c = new Animal('male',5);
			var d = c;
			d.grander = 'female';
			//深克隆一
			var e = new Animal('male',5);
			var f = JSON.parse(JSON.stringify(e));
			//深克隆二
			var g = new Animal('male',{type:'older',age:5});
			var h = deepclone(g);
			h.age.type = 'younger';
			//遞迴方法
			function deepclone(object){
				var result;
				if(isObject(object)=='Object')
					result = {};
				else if (isObject(object)=='Array')
					result = [];
				else
					return object;
				for(var key in object){
					var copy = object[key]
					if(isObject(copy)=='Object')
						result[key] = deepclone(copy);
					else if(isObject(copy)=='Array')
						result[key] = deepclone(copy);
					else
						result[key] = copy;
				}
				return result;
			}
			//判斷物件,基本型別,陣列
			function isObject(object){
				var result = Object.prototype.toString.call(object).slice(8,-1);
				return result;
			}
			g.grander = 'female';			
			a.plainProp = 'hello';
			a.objectProp.age = 100;
			console.log(a.objectProp);//'100'
			console.log(b.objectProp);//'100'----修改錯誤
			//原型替換
			a.objectProp= {'age':200};			
			console.log(a.plainProp);//'hello'
			console.log(b.plainProp);//'hi'
			console.log(a.objectProp);//'20'
			console.log(b.objectProp);//'200'
			b.objectProp.age = 300;
			console.log(a.objectProp);//'20' ----原型替換
			console.log(b.objectProp);//'300'
			
			console.log(a.hasOwnProperty('plainProp'))//'true'
			console.log(b.hasOwnProperty('objectProp'))//'false'
			console.log('==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
			console.log(c.grander)//'female'
			console.log(d.grander)//'female'
			console.log('==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
			console.log(e.grander)//'male'
			console.log(f.grander)//'female'
			console.log('==============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
			console.log(g.age.type)//'older'
			console.log(h.age.type)//'younger'

構造物件是發生了什麼?


  1. 從上面的圖示中可以看到,建立p1物件雖然使用的是Person建構函式,但是物件創建出來之後,這個p1物件其實已經與Person建構函式沒有任何關係了,p1物件的[[ prototype ]]屬性指向的是Person建構函式的原型物件。
  2. 如果使用new Person()建立多個物件,則多個物件都會同時指向Person建構函式的原型物件。
  3. 我們可以手動給這個原型物件新增屬性和方法,那麼p1,p2,p3…這些物件就會共享這些在原型中新增的屬性和方法。
  4. 如果我們訪問p1中的一個屬性name,如果在p1物件中找到,則直接返回。如果p1物件中沒有找到,則直接去p1物件的[[prototype]]屬性指向的原型物件中查詢,如果查詢到則返回。(如果原型中也沒有找到,則繼續向上找原型的原型—原型鏈。 後面再講)。
  5. 如果通過p1物件添加了一個屬性name,則p1物件來說就遮蔽了原型中的屬性name。 換句話說:在p1中就沒有辦法訪問到原型的屬性name了。
  6. 通過p1物件只能讀取原型中的屬性name的值,而不能修改原型中的屬性name的值。 p1.name = “李四”; 並不是修改了原型中的值,而是在p1物件中給添加了一個屬性name。