javascript 對象及原型繼承有關的屬性:constructor、prototype、isPrototypeOf、instanceof、in 、hasOwnProperty 等等

來源:互聯網
上載者:User

constructor:對象的構造器,是一個函數。

prototype:構造器的原型,只有函數才具有這個屬性。

isPrototypeOf:如果對象 A 存在於 對象obj的原形鏈中,則 A.isPrototypeOf(obj)返回true,而obj必定繼承了A 的屬性。

__proto__:訪問對象的原型鏈在當前對象的上一級對象,即對象的父級對象,非W3C 或 ECMAscript 標準,是瀏覽器對原型繼承 的一種實現手段,存在於firefox 和 chrome ,IE下不存在這個屬性。js 對象的原形鏈應當是由 js 引擎維護的,屬於“引擎級”的資料,__proto__ 屬性的出現使原形鏈可以被修改,這使得在 js 文法範圍內討論 js 對象的原型鏈稱為可能。

在對象的繼承關係中,對象obj的構造器 constructor 其實是存在於原型鏈中的,即 obj.constructor 實際上 是 obj.__proto__.constructor,  obj.hasOwnProperty('constructor');  為 false

function Y() {this.y=99;}var obj = new Y(); console.log(obj.constructor); //Yconsole.log(obj.hasOwnProperty('constructor')); //falseconsole.log(obj.__proto__.hasOwnProperty('constructor')); //true //=====function X(){this.x=88; }function Y() {this.y=99;}Y.prototype = new X();var obj = new Y(); console.log(obj.constructor); //Xconsole.log(obj.hasOwnProperty('constructor'));//falseconsole.log(obj.__proto__.hasOwnProperty('constructor')); //falseconsole.log(obj.__proto__.__proto__.hasOwnProperty('constructor')); //true 
//============
//訪問對象時,對於 obj.__proto__.x=value 則必定有 obj.x=value,//obj.constructor.prototype 上的屬性將被儲存在obj.__proto__中。 function Y() {this.y=99;} Y.prototype = {a:11}; var obj = new Y(); obj.__proto__.hasOwnProperty("a");//true Y.prototype.a=77; console.log([obj.a,obj.__proto__.a,obj.y,obj.__proto__.y]); //77,77,99,undefined,y 屬性是由物件建構器直接產生的而不是從原形鏈繼承來的*/

//new 運算構造obj對象之後,obj訪問繼承來的屬性時,是通過__proto__ 訪問的,而不是通過obj.constructor.prototype 訪問,obj.__proto.__ 並非簡單指向 obj.constructor.prototype,而是與它指向同一個對象
//因此,如果修改obj.constructor.prototype指向另一個對象,並不會影響obj繼承原有的屬性。 

Y.prototype = {b:22};
console.log(obj.b); //undefined
console.log(obj.a); //77

 

//另一例子,可能會帶來一點迷惑function ClassA(){    var prop = 'hello';    arguments.callee.prototype={           getProp:function(){                  return prop;           }   }}var obj1 = new ClassA();obj1.getProp(); // error,Object #<ClassA> has no method 'getProp'var obj2 = new ClassA();obj2.getProp(); // hello因為初始化 obj1 時,ClassA.prototype 被修改,而修改前,obj1 已經執行個體化了

 

in:如果對象 obj  有屬性 property(包括繼承來的和不可列舉屬性,不同於 for in 迴圈中的 in,for in 忽略了 不可列舉屬性), 則'property' in obj 返回 true,這個運算不存在於初期版本的javascript。

 

propertyIsEnumerable:如果對象obj上的屬性property可以被列舉出來(可被 for in 迴圈遍曆), 則 obj.propertyIsEnumerable('property') 返回true,值得注意的 是,propertyIsEnumerable對繼承來的屬性一律判斷為false,這一般被認為是ECMA Script 規範的一個設計上的錯誤。

 

hasOwnProperty:如果對象obj 上的屬性 property 不是繼承的來的,則 obj.hasOwnProperty('property') 返回true。

 

delete:刪除對象自身上的屬性,不能刪除繼承來的屬性,不能刪除使用 var 聲明的變數 ,不能刪除函式宣告,但是在如果在 firebug 和 IE9 的調試器裡面執行代碼,會發現全域變數被刪除了,實際上這在頁面上的代碼中是不會發生的事

 

var f = function(){};f.prototype = { x:99 };var o = new f;console.log(o.hasOwnProperty('x')); //falseconsole.log(o.x); //99delete o.x ;console.log(o.x); //99 var x = 1;window.hasOwnProperty('x'); //truedelete window.x;console.log(x); // error,x is not defined in firefox bug , it will be 1 in chrome

 

instanceof:如果obj對象是建構函式Fun的一個執行個體,則 obj instanceof Fun 返回 true,

值得注意的是,instanceof 並不檢查 Fun 函數,其檢測是基於"原形鏈"的,如果 fun.prototype == obj.__proto__ 為 true, 或者 fun.prototype.isPrototypeOf(obj.__proto__)  為 true , 則 obj instcaneof fun 返回 true,即 fun.prototype.isPrototypeOf(obj) 為 true . (之前這裡寫 instanceof 以 fun.prototype.constructor==obj.__proto__.constructor 是否為 true 作為 依據是錯誤的 )

因此,即使 obj instanceof Fun 返回 true,obj 也可能不具有 Fun 構造器中定義的屬性,因為 Fun 不一定是 obj 的構造器。

試看下面代碼:

function f(){};function g(){};function k(){}f.prototype = new g();var obj = new f();console.log(obj instanceof f,obj instanceof g,f.prototype==obj.__proto__,g.prototype.isPrototypeOf(obj.__proto__)) ; //true true true truek.prototype = f.prototype;console.log(obj instanceof k); //truevar o = {};o.__proto__ = obj;console.log(o instanceof f); //truefunction P(){}P.prototype.constructor = obj.__proto__.constructor;console.log(obj instanceof P.prototype.constructor, obj instanceof P); //true falseobj.__proto__ = {};console.log(obj instanceof f); //falseg.prototype = {};console.log(obj instanceof g); //false
//另一個例子function A(){   this.a='a';}function B(){  this.b = 'b';}B.prototype.constructor = A;var obj = new B();console.log(obj instanceof B, obj instanceof A); //true ,false console.log(B.prototype==obj.__proto__); //trueconsole.log(obj.constructor === A,obj.__proto__.constructor ===A, obj instanceof A); //true true false , 這說明 instanceof 不以構造器為判斷依據

 

關於instanceof,試考察下面代碼: 

    function P(){this.p=11;};    var pro = new P();     function X() {this.x=88;}      function Y() {this.y=99;}      Y.prototype =pro;     var obj = new Y(); 

 

    1、物件建構器在哪

    console.log(obj.hasOwnProperty('constructor')); //false    console.log(obj.constructor); //P    console.log(obj.__proto__.constructor);//P    console.log(obj.__proto__.constructor === Y.prototype.constructor); //true
 

這說明執行new時,obj.constructor 即 obj.__proto__.constructor ,obj.__proto__ ==  Y.prototype;
因此  obj.constructor 實際是 Y.prototype.constructor 而不是 Y,
因此,“物件建構器” 實質上應是 “對象原型的構造器”,   即, 當 obj 對象的建構函式的 prototype.constructor 不是指向自身時, obj.constructor 不是指向 obj 的構造器,而是 obj 對像的原型的構造器。

    

    2、物件建構器修複

    但是,有一點小問題,考察一下 y 屬性:

 

    console.log(obj.y); // 99    console.log(obj.__proto__.y); //undefined

    y 屬性既然不是來自於“原型鏈”,那自然是來自於物件建構器,但是 P 函數中並沒有定義 y 屬性,

    從“類式繼承” 形成的“繼承鏈” 看來,P 只是“繼承鏈”的源頭,也就是最頂級的 “基類”, obj 對象執行個體的的構造來源於“子類” y 函數,

    這是 js 對象繼承系統中 “類比類式繼承” new 與“原型繼承” prototype 之間的一點裂縫,

    很多人執著於修複這個裂縫,於是有了構造器修複的做法.

    預設狀態下聲明一個函數fun,有 fun.prototype.constructor===fun,於是:

 

    obj.constructor =  Y ; //修複構造器,賦一個constructor 屬性來覆蓋掉繼承鏈上的constructor     console.log(obj.hasOwnProperty('constructor')); //true    console.log(obj.constructor); //Y    console.log(obj.__proto__.constructor); //P  

//或者向下面這個構造器處理方式
var fun = (function(){
var f = function(){
this.a =1;
};
f.prototype = {
constructor:f, //修複構造器為函數 f,因為直接將一個對象直接量賦給 f.prototype,fun構造的對象的constructor 將是對象直接量的constructor,即 Object函數
method1:function(){
return this.a;
}
};
   return f;
})();

var obj = new fun();

 

 

    3、obj instancof Fun 為 true 並不意味著 Fun 一定是 obj 對象的構造器,Fun 可能並不存在於 obj 的繼承鏈中:

    X.prototype = pro;    console.log(obj instanceof X); //true    console.log(obj.x);//undefined , X 不是 obj 的構造器    console.log(obj instanceof Y); //true    console.log(obj.y);//99

 

  4、Object.create()

  新版本的 ECMAScript 為 Object 對象擴充了一些方法,

  Object.create(pro)可以基於 pro 為原型建立一個對象,其效果相當於  

    var f = function(){};    f.prototype = pro;    var obj = new f();

   

    //try:    function P(){this.p=11;}    function K(){this.k=22;}    function F(){this.f=33;}    var pro = new K();    P.prototype = pro;    var o= new P();     var obj = Object.create(o);      console.log(o,obj); // 都是 {p:11,k:22}    console.log(obj.constructor); // K    console.log(obj.__proto__.constructor); //k    console.log(obj instanceof P); //true    console.log(obj instanceof K); //true     console.log(obj instanceof F); //false    F.prototype = pro;    console.log(obj instanceof F); //true

 

 

  5、Object 與 Function:

  

console.log(Function instanceof Object); //trueconsole.log(Object instanceof Function); //true

  先有 Function 還是先有 Object ?下面這個現象或許能解釋,Object 才是“最頂級”的對象

  console.log(Object.__proto__.__proto__===Function.prototype) ; // false  console.log(Function.__proto__.__proto__ === Object.prototype); // true  console.log(Object.prototype.__proto__); // null ,Object 的對象原型已經是女媧級的了
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.