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