JS中有關對象的繼承以及實例化、淺拷貝深拷貝的奧秘


一、屬性的歸屬問題

JS對象中定義的屬性和方法如果不是掛在原型鏈上的方法和屬性(直接通過如類似x的方式進行定義)都只是在該對象上,對原型鏈上的沒有影響。對於所有實例共用的方法可直接定義在原型鏈上這樣實例化的的時候就不用對每個實例定義該屬性方法,所有的實例均具有該方的引用見最后的輸出。

function Myclass(){

this.x=" x in Myclass";

this.get=function(){}//每次實例化對象,每個對象的該方法都是獨立的,是不相同的

}

Myclass.prototype.y="y in Myclass";

Myclass.prototype.set=function(){};//所有實例共用該方法,對於該方法具有同一個實例

var obj=new Myclass();

console.log(obj.y);//y in Myclass

obj.y="override y";//查找屬性時現在當前的對象上找,沒找到才到原型鏈上查找

console.log(obj.y);//override y

delete obj.y //true

console.log(obj.y);//y in Myclass

var obj2=new Myclass();

console.log(obj2.y);//y in Myclass

obj.z='zzz'; 

console.log(obj.z);//zzz

console.log(obj2.z);//undefined

console.log(obj.prototype);//undefined

console.log(obj.get===obj2.get)//false;

console.log(obj.set===obj2.set)//true,所有的實例具有相同的引用

二、JS中有關原型的__proto__和prototype的差別:

所有的實例對象都具有__proto__來表示其原型,prototype是方法具有的屬性,非對象的方法的該屬性為null,這兩者都用於表示對象的原型鏈,由於很多場合下前者是私有屬性一般不直接使用故可以用Object.getPrototypeOf(obj)的方式獲取到原型對象,Object.create()中傳入的即為創建對象的原型。

function Myclass(){

this.x=" x in Myclass";

this.get=function(){}//每次實例化對象,每個對象的該方法都是獨立的,是不相同的

}

Myclass.prototype.y="y in Myclass";

Myclass.prototype.set=function(){};//所有實例共用該方法,對於該方法具有同一個實例

var obj=Object.create(new Myclass());

//obj.__proto__.y=10;

console.log(obj.__proto__);

console.log(Myclass.prototype);

var obj2=new Myclass();

console.log(Myclass.prototype===obj.__proto__.__proto__);//ture

console.log(obj.x);

console.log(Object.getPrototypeOf(obj2)===Myclass.prototype);//true

三、對象的實例化和繼承

   利用new進行實例化對象,利用原型(prototype)實現繼承,在繼承時只會繼承原型鏈上的屬性和方法,不會繼承掛在對象自身上的屬性和方法,實例化時對象具有所有的屬性和方法。

function Myclass(){

this.x=" x in Myclass";//每次實例化對象,每個對象的該方法都是獨立的,沒有被繼承

this.get=function(){}

}

Myclass.prototype.y="y in Myclass";

Myclass.prototype.set=function(){};//所有實例共用該方法,對於該方法具有同一個引用,定義在原型鏈上的屬性和方法都會被繼承

var obj=Object.create(Myclass.prototype);//create的第一個參數必須是原型,第二個參數用於定義屬性和defineProperties/defineProperty使用方法相同

console.log(obj.x);//undefined

console.log(obj.y);// y in Myclass

    因而可以通過混合模式定義對象實現屬性或者方法的部分繼承,不想被繼承的利用構造函數的方式this.property方式定義,想要被繼承的直接定義在原型鏈上(如上面的只繼承了y屬性和set方法,其他的x等就沒有被繼承)。不過如果直接實例化會具有所有的屬性和方法。通過create的方式則只具有繼承的屬性和方法。

//繼承的時利用實例化的對象作為原型不會影響原對象實例化出來的對象

function Myclass(){

this.x=" x in Myclass";

this.get=function(){}//每次實例化對象,每個對象的該方法都是獨立的,是不相同的

}

Myclass.prototype.y="y in Myclass";

Myclass.prototype.set=function(){};//所有實例共用該方法,對於該方法具有同一個實例

function obj(){};

obj.prototype=new Myclass();

var obj1=new obj();//利用create出來的對象是實例是不能實例化的

obj1.x=12;

var obj2=new Myclass();

console.log(obj2.x);//  x in Myclass

console.log(obj1.x); //12

1、JS中可以直接使用delete對對象的屬性進行刪除,但是不能刪除原型鏈上的屬性,和普通變量,同時當對象中的屬性配置false時不可以刪除該屬性

  1,對象屬性刪除(delete無法刪除原型鏈上的屬性)

function fun(){

this.name = 'mm'; 

}

var obj = new fun();

console.log(obj.name);//mm

delete obj.name;

console.log(obj.name); //undefined

2,變量刪除(在嚴格模式下不能利用delete刪除變量)

var name = 'lily';

delete name;

console.log(name); //lily

 

直接用delelte刪除不了變量

3,刪除不了原型鏈中的變量

fun.prototype.age = 18;

delete obj.age;

console.log(obj.age) //18

四、對象的淺拷貝深拷貝

深拷貝、淺拷貝:

淺拷貝:不會繼續對對象里面的對象進行解析賦值

function deepCopy(p, c) {

    var c = c || {};

    for (var i in p) {

     c[i] = p[i];     

    }

    return c;

  }

深拷貝:

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;

  }

 

比較兩個對象那個是否相等如果直接用==、===比較的是對象的引用,當對象的引用是相同的時則相等。上訴進行拷貝的方式對象那個都是不相等的,只有賦值的才是相等的。所以判斷對象是否相等要注意是只要屬性名稱、個數、值直接相等就是相等還是通過類型引用判斷的。

五、對象中常用的方法

1、通過Object.preventExtention(a)可以對a對象禁止擴展

2、利用Object.seal()對對象進行密封是的對象不可配置和重新賦值

3、利用Object.freeze()對對象進行凍結使對象只能夠讀取,這個只是淺操作,當對象的屬性還是對象時可以修改其嵌套的對象的值

4、訪問對象中的屬性如果沒有定義會返回undefined但是訪問沒有定義的變量時會提示  Uncaught ReferenceError

5、對象中判斷某個屬性是否存在的方法:

(1)‘a’ in myobject 判斷a屬性是否在myobject中(會對原型鏈進行查找)

(2)myobject.hasOwnProperty(‘a’)這個只會當前對象上查找自生的屬性是否存在但是不會在原型鏈上查找。

以上兩種方式都可以對不可枚舉的屬性進行查找

不可枚舉的屬性是不能被遍歷得到的

6、propertyIsEnumerale()用於判斷屬性是不是可枚舉的

7、Object.keys()用於獲取所有自身的可枚舉屬性的屬性名(不包括原型鏈上繼承的)

8、for in 循環可遍歷對象那個所有的自身以及集成的可枚舉的屬性

9、Object.hasOwnProperty()判斷某個屬性是不是對象自身的屬性(其中包括不可枚舉的),利用for in結合即可獲取所有自身可枚舉屬性

10、Object.getOwnPropertyNames()獲取對象自身的所有的屬性名

JS中的對象(如數組、方法、object)直接賦值給其他變量傳遞的是對象的引用,賦值后會相互影響。如: var aa={a:1,b:2};

var bb=aa;//直接將aa對象賦值,其實是將aa對象的引用賦給bb

bb.a=2;

console.log(aa);//Object {a: 2, b: 2},aa的結果受到影響。

對象直接賦值會導致動一處導致多處影響,所以最好利用拷貝的方式進行賦值。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM