1. 程式人生 > >JS面向物件,建立,繼承

JS面向物件,建立,繼承

      很開心,最近收穫了很多知識,而且發現很多東西,以前理解的都是錯的,或者是膚淺的,還以為自己真的就get到了精髓,也很抱歉會影響一些人往錯誤的道路上走,不過這也告訴了我們,看任何一篇文章都不能盲目的去相信,要實踐驗證再驗證。今天就重新整理一下,我對面向物件的理解,當然也不保證完全正確的,但絕對是在進步的,拋磚引玉,希望能帶來一些新的感悟。

     物件,通俗的來說,就是屬性和方法。定義就不再多說,下面說物件的建立:

1 建立一個物件

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

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

2  工廠方式

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();

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

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

3 建構函式模式

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

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();

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

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

function CreatePerson(name){   
  this.name = name; 
  this.showName = function(){ 
    alert(this.name); 
  };
  console.log(this);
} 

new CreatePerson('haha'); //CreatePerson{}
CreatePerson('haha');  //window

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

function CreatePerson(name){   
  var res = {};  //宣告一個空物件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;//返回這個物件
} 

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

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

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

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

4 原型+構造模式

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

看個栗子(原型+構造)

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

    通過最後一句的測試為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的原型物件。

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

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

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

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

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

function CreatePerson(name){
   this.name = name;
}
CreatePerson.prototype.showName = function(){
  console.log(this.name);
};
var p1 =new CreatePerson('haha');
p1.showName();
console.log(p1.constructor);  // CreatePerson   來自CreatePerson.prototype
console.log(CreatePerson.prototype); // {showName:function(){},constructor:CreatePerson,__proto__:Object.prototype} //可見,原型物件儲存了1 自身新增的方法,2 建構函式constructor 3 _proto_(和上一層建構函式原型物件的連線) console.log(CreatePerson.prototype.__proto__===Object.prototype);// true 這個原型物件本身又是object的例項化物件,所有_proto_指向Object的原型物件 console.log(CreatePerson.prototype.__proto__===Object);// false 可見是和建構函式下原型物件的連線,不是建構函式 console.log(CreatePerson.prototype.constructor);//CreatePerson 預設有的 指向創造它的函式 console.log(Object.prototype.__proto__); // null 原型鏈的終點是null console.log(CreatePerson.__proto__); //function.prototype CreatePerson本身既是建構函式又是function的例項化物件,擁有_proto_屬性,指向function的原型物件 console.log(CreatePerson.constructor); // function 繼承自function.prototype

console.log(CreatePerson.prototype instanceof CreatePerson ) //驗證是否在一條原型鏈上 false

字面量法定義原型

為了建立物件的程式碼更方便,你一定見過這樣的程式碼,就是字面量法:

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屬性,就去上級原型物件找,找到了Object
console.log(a1.constructor );//Object 也變了,驗證了它是訪問的原型物件上的
因此我們在寫的時候需要修正一下原型的指向:
function Aaa(){}
Aaa.prototype = {
  constructor:Aaa,
  num1:function(){alert(10);}
} 
var a1 = new Aaa(); 
a1.constructor // Aaa

 理解了這些,繼承就很好理解了,下回繼續補充。有錯誤,歡迎糾正。

相關推薦

Js面向物件程式設計——建立物件(工廠模式)

建立物件——工廠模式 建立物件——工廠模式 建立物件——工廠模式 工廠模式是軟體工程領域一種廣為人知的設計模式,這種模式抽象了建立具體物件的過程。考慮到在ECMAScript種無法建立類,開發人員就發明了一種函式,用函式來封裝以特定介面

Js面向物件程式設計——建立物件動態原型模式

建立物件動態原型模式 動態原型模式 動態原型模式 有其他OO語言經驗的開發人員在看到獨立的建構函式和原型時,很可能會感到非常困惑。動態原型模式正式時致力於解決這個問題的一個方案,它把所有資訊都封裝在了建構函式中,而通過在建構函式中初始化

JS面向物件建立繼承

      很開心,最近收穫了很多知識,而且發現很多東西,以前理解的都是錯的,或者是膚淺的,還以為自己真的就get到了精髓,也很抱歉會影響一些人往錯誤的道路上走,不過這也告訴了我們,看任何一篇文章都不能盲目的去相信,要實踐驗證再驗證。今天就重新整理一下,我對面向物件的理解,當然也不保證完全正確的,但絕對是在進

js:面向物件程式設計帶你認識封裝、繼承和多型

週末的時候深入的瞭解了下javascript的面向物件程式設計思想,收穫頗豐,感覺對面向物件程式設計有了那麼一丟丟的瞭解了~很開森 什麼是面向物件程式設計 先上一張圖,可以對面向物件有一個大致的瞭解,然而什麼是面向物件呢,用java中的一句經典語

面向物件模型分析(繼承多型)

class是一種特殊的struct 在記憶體中 class 依舊可以看做變數的集合 class 中的成員函式和成員變數是分開存放的 每個物件有獨立的成員變數 所有物件共享類中的成員函式

Java程式設計師從笨鳥到菜鳥之(三)面向物件之封裝繼承多型(下)

五:再談繼承   繼承是一種聯結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。物件的一個新類可以從現有的類中派生,這個過程稱為類繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那裡繼承方法和例項變數,並且類可以修改或增加

Python基礎(14):面向物件高階(多重繼承定製類列舉類元類)

一,多重繼承 定義:一個子類可以繼承自多個父類 目的:同時擁有多個父類的所有功能,且減少設計層次。 Mixln:某子類中,需要混入額外功能,可以通過多重繼承實現,這種設計,被叫做Mixln 二,定製類 解釋:通過魔術方法的定義,是自定義的類滿足某些特性。 __str__:

Js面向物件程式設計——屬性型別訪問器屬性

Js面向物件程式設計——屬性型別,訪問器屬性 訪問器屬性 訪問器屬性 訪問器屬性不包含資料值;它們包含一對兒getter和setter函式(不過,這倆個函式都不是必需的)。在讀取訪問器屬性時,回撥用getter函式,這個函

js -- 理解面向物件建立物件繼承

目錄 二、繼承 1. 原型鏈 宣告: 部落格中關於js篇都是在node環境下測試,若在瀏覽器中有些地方結果可能有所不同但原理相同。 一、建立物件 1. 工廠函式模式  該模式抽象了建立具體物件

js面向物件寫法一個小例子

/** * * 這是一個校驗檔案 */ var MyValidation = function(){ //校驗資料庫 this.validDatabase = function

js面向物件思想封裝拖拽功能相容pc和移動端

我們在開發專案過程中,很可能會碰到頁面上某塊需要可以拖拽移動的功能需求,網上已經有不少前輩分享了相關功能的案例,外掛或者程式碼,但是考慮到專案功能需求,我們可能僅需要實現拖拽移動功能就可以,不需要其他功能,而網上很多外掛往往附帶了其他功能需求。這裡筆者僅對拖拽移

黑馬程式設計師---面向物件上(封裝繼承多型)

------<a href="http://www.itheima.com" target="blank">Java培訓、Android培訓、iOS培訓、.Net培訓</a>、期待與您交流! 面向物件(Object-Oriented,簡稱OO)

java 面向物件面試題問答題構造方法抽象類繼承多型介面異常總結;

一,構造方法的特點 面向物件的思想是如何在java展現的呢? 就是通過類和物件 類是一組相關的屬性和行為的集合。是一個抽象的概念。 物件是該類事物的具體表現形式。具體存在的個體。 一、抽象類的抽象方法的特點是什麼? 被abstract修飾的類稱為抽象類 特點: 1、抽象類不能有物件(不能用new關鍵字來例項化

原生js日曆選擇器學習js面向物件開發日曆外掛

在web開發過程中經常會碰到需要選擇日期的功能,一般的操作都是在文字框點選,然後彈出日曆選擇框,直接選擇日期就可以在文字框顯示選擇的日期。開發好之後給使用者使用是很方便,但如果每一個日曆選擇器都要臨時開發的話,會嚴重影響專案進度。所以網上有很多日曆外掛提供下載使用。 在實際工作中,日曆選擇器功能確實都是直接使

js面向物件繼承

     function Person(name,sex){ // var this=new Object();//這裡註釋的程式碼 假想 new操作時系統內部幫我們做了這些 this.name=name; this.s

面向物件程式設計介紹類和物件

想一想 請用程式描述如下事情: A同學報道登記資訊 B同學報道登記資訊 C同學報道登記資訊 A同學做自我介紹 B同學做自我介紹 C同學做自我介紹 stu_a = { “name”:“A”, “age”:21, “gender”:1, “hometown”:“河北” } stu_b = {

js面向物件原型和繼承

js面向物件原型和繼承作用域鏈和閉包 原型 我們都知道,函式建立時瀏覽器會在記憶體中建立一個物件。很多人在這裡都感覺很難理解裡面的關係 函式建立的時候,瀏覽器會在記憶體中建立一個由prototype指向的物件。其實只有當你要將函式作為建構函式使用的時候,創建出來的物件才會發揮作用

JVM學習(二)類的載入物件建立記憶體分配及訪問定位

參考資料:   《深入理解java虛擬機器》    https://www.cnblogs.com/chenyangyao/p/5245669.html    https://blog.csdn.net/qq_41907991/artic

面向物件——三大特性六大原則

什麼是面向物件 面向物件是軟體開發方法。面向物件的概念和應用已經超越了程式設計和軟體開發,擴充套件到如資料庫系統,互動式介面,應用結構,應用平臺,分散式系統,網路管理結構,CAD技術,人工只能等領域。面向物件是一種對現實世界理解和抽象的方法,是計算機程式設計技術發展到一定階

五個學生每學生有3門課的成績 * 從鍵盤輸入以上資料(學生號姓名三門課成績) * 計算出 平均成績(採用面向物件的方式如學生

/**  * 有五個學生,每學生有3門課的成績,  * 從鍵盤輸入以上資料(學生號,姓名,三門課成績),  * 計算出 平均成績(採用面向物件的方式,如學生類。。。)。  * @author chenkunqing  *  time : 2017/7/21-16