JS物件導向,建立,繼承

來源:互聯網
上載者:User

標籤:request   瀏覽器   cookie   

1 建立一個物件導向

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

var obj = new Object(); //建立一個Null 物件obj.name = ‘haha‘;obj.showName = function(){    alert(obj.name);}obj.showName();

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

缺點:當我們想建立多個物件導向的時候,重複代碼過多,需要封裝,所以有了下面的方法

2  工廠方式

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function CreatePerson(name){     //原料   var obj = new Object();    //加工   obj.name = name;   obj.showName = function(){        alert(this.name);   }   //出廠   return obj;}var p1 = CreatePerson(‘haha‘);p1.showName();var p2 = CreatePerson(‘hehe‘);p2.showName();

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

這其實就是簡單的封裝函數,整個過程像工廠的流水線,所以叫工廠方式

缺點:無法識別建立的對象的類型。因為全部都是Object,沒有區分度,不像Date、Array等,因此出現了建構函式模式。

3 建構函式模式

我們要通過這二個方面來改變:1 函數名首字母大寫  2 New 關鍵字調用

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function CreatePerson(name){      this.name = name;      this.showName = function(){         alert(this.name);      } } var p1 =new CreatePerson(‘haha‘);  p1.showName();var p2 = new CreatePerson(‘hehe‘); p2.showName();

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

1首字母大寫,是為了區別於普通的函數,建構函式本身就是普通的函數,只是我們專門用它來實現了構造的功能,所以專門起了一個名字叫建構函式,任何函數都可以成為建構函式,這取決於你調用函數的方式。是否用了New。

2 調用函數的時候用了 New關鍵字,那麼New到底做了什嗎?用不用New有什麼區別?再來看下面的例子

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function CreatePerson(name){     this.name = name;   this.showName = function(){     alert(this.name);   };  console.log(this);} new CreatePerson(‘haha‘); //CreatePerson{}CreatePerson(‘haha‘);  //window

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

我們會發現當用New去調用一個函數的時候,this的指向會不一樣。其實New主要做了下面這些事,不過下面寫的只是大概的行為,並不是內部源碼。

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function CreatePerson(name){     var res = {};  //聲明一個Null 物件res  res._proto_= CreatePerson.prototype;//這個對象的_proto_屬性指向建構函式的原型對象,這樣res就可以調用CreatePerson原型對象下的所有方法  CreatePerson.apply(res);//把this指向改為res對象  this.name = name;  //res對象添加屬性,方法  this.showName = function(){     alert(this.name);   };  return res;//返回這個對象}

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

關於New做時候都是內部的行為,看不到但確實存在,關於上面原型可以先大概知道結論,下面會說原型,接著看就懂了。

函數構造模式存在的問題:

alert(p1.showName==p2.showName);//false

測試這個代碼,兩個方法是不相同的,也就是說這兩個對象並不是共用一個方法,每new一次,系統都會新建立一個記憶體,這兩個對象各自有各自的地盤,但他們具有相同的功能,還不共用,肯定不是我們所希望的。所以就有了下一種方法,原型+構造模式

4 原型+構造模式

每個函數都有一個prototype屬性,它是一個對象,也稱作原型對象,這個原型對象,我們可以把方法和屬性寫在它上面(不過原型對象不僅僅有我們寫的屬性和方法,還有別的,下面會介紹),而通過這個函數建立出來的執行個體對象,都能共用這個原型對象下的方法和屬性。所以我們只需要把想要共用的東西放在函數的prototype下,不想共用的東西通過建構函式來建立就可以了。

看個栗子(原型+構造)

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function CreatePerson(name){     this.name = name;}CreatePerson.prototype.showName = function(){     alert(this.name);}var p1 =new CreatePerson(‘haha‘);p1.showName();var p2 = new CreatePerson(‘hehe‘);p2.showName();alert(p1.showName==p2.showName);//true

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

    通過最後一句的測試為true,可以看到在建構函式的原型下面加的方法showName()方法是所有通過這個建構函式建立出來的對象所共用的,也就是說他們共用一個記憶體,更進一步的說它們存在參考關聯性,也就是說你更改了p1的showName也會影響p2的showName。

    所以我們在構造對象的時候,一般是原型模式和構造模式組合使用,變化的用構造模式 不變的公用的用原型模式,就像上面的這個栗子,屬性用的建構函式,因為一般不同對象屬性都不同,方法用原型模式。

 _proto_屬性:同一個函數造出來的執行個體對象能共用這個函數的prototype下的方法和屬性,但是它是如何做到的呢?這裡要出場的就是_proto_屬性,每個執行個體化對象都有一個_proto_屬性,它是一個指標,指向函數的prototype,也就是儲存了它的地址。(JS中任何對象的值都是儲存在堆記憶體中,我們聲明的變數只是一個指標,儲存了這個對象的實際地址,所以有了地址就能找到對象),所以總得來說,每個執行個體化對象都有_proto_屬性,儲存了建構函式的原型對象的地址,通過這個屬性就可以擁有原型對象下的所有屬性和方法,_proto_屬性實際就是執行個體化對象和原型對象之間的串連。

原型鏈: 每個函數都可以成為建構函式,每個函數都有原型對象,每個原型對象也可以是一個執行個體化對象,比如,你建立了一個函數fun,它是建構函式function的執行個體化對象,而function的原型對象,又是Object的執行個體對象。所以fun有個_proto_屬性可以訪問到function的原型對象,function原型對象也是個執行個體對象,也有個_proto_屬性,可以訪問到Object的原型對象,所以通過_proto_屬性,就形成了一條原型鏈。每個執行個體化對象都可以訪問到鏈子上方的方法和屬性,所以fun是可以訪問Object原型對象下的方法和屬性的。實際上所有對象都可以訪問到Object的原型對象。

原型鏈的訪問規則:先在自身的下面尋找,再去一級一級的往原型鏈上找。如下:

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function Aaa(){}Aaa.prototype.num = 3;var a1 = new Aaa();a1.num =10;alert(a1.num); //10

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

650) this.width=650;" src="http://images2015.cnblogs.com/blog/924161/201705/924161-20170503125720601-1696320537.png" width="624" height="167" style="margin:0px;padding:0px;border:0px;" />

原型對象下的方法和屬性:原型對象下面可能有三大類:1 原型對象所帶方法和屬性   2 constructor   3 _proto_

constructor:建構函式屬性,每個函數的原型對象都有的預設屬性,指向函數。每個執行個體化對象本身是沒有constructor屬性的,每個執行個體化對象下面都預設只有一個_proto_,用來串連原型對象,而和建構函式本身是沒有直接的聯絡的。所以它的constructor是訪問的原型對象上的。所以當原型對象的constructor變化了,執行個體化對象的constructor也會改變。但是如果這個對象本身既是原型對象,又是執行個體化對象,那就擁有了constructor屬性,無需從原型對象繼承。

看下面的例子,來驗證我們所說的:

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

.name ==  p1 = CreatePerson(‘haha‘console.log(CreatePerson.prototype.__proto__===Object.prototype);console.log(CreatePerson.prototype.__proto__===Object);console.log(CreatePerson.constructor); console.log(CreatePerson.prototype  CreatePerson )

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

字面量法定義原型

為了建立對象的代碼更方便,你一定見過這樣的代碼,就是字面量法:

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function Aaa(){}Aaa.prototype = {    showName:function(){alert(10);}}; var a1 = new Aaa();console.log(Aaa.prototype);//{showName:function(){},_proto_}   你會發現constructor不見了,因為這種方式相當於重新賦值了Aaa.prototype console.log(Aaa.prototype.constructor);//Object  因為自身沒有了constructor屬性,就去上級原型對象找,找到了Objectconsole.log(a1.constructor );//Object 也變了,驗證了它是訪問的原型對象上的

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

因此我們在寫的時候需要修正一下原型的指向:

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

function Aaa(){}Aaa.prototype = {  constructor:Aaa,  num1:function(){alert(10);}} var a1 = new Aaa(); a1.constructor // Aaa

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />


JS物件導向,建立,繼承

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.