JavaScript(5)--- 面向對象 + 原型

面向對象 + 原型

面向對象這個概念並不陌生,如 C++、Java 都是面嚮對象語言。面向對象而言都會現有一個類的概念 ,先有類再有對象。類是實例的類型模板。javascript

好比人類 是一個類 張三 李四 就是一個個對象,他們都是人類建立出的對象 因此都有人類的共同特性,好比 人類都會吃飯 人類都會走路 因此張三李四也會吃飯和走路。java

JavaScript 沒有類的概念,是基於原型的面向對象方式。它們的區別在於:編程

在基於類的面向對象方式中,對象(object)依靠類(class)來產生。
在基於原型的面向對象方式中,對象(object)則是依靠構造函數(constructor)和原型(prototype)構造出來的。

面嚮對象語言的第一個特性毫無疑問是封裝,在 JS 中,封裝的過程就是把一些 屬性方法 放到對象中「包裹」起來。segmentfault

1、建立對象三種方式

一、原始方式建立對象

1) 字面量的方式設計模式

示例函數

var per = {
            name: "張三",
            age: 20,
            sex: "男",
            say: function () {
                console.log("說話");
            }
        };

2) Object實例添加屬性方法學習

示例this

var per2=new Object();
           per2.name="李四";
           per2.age=30;
           per2.sex="男";
           per2.say=function () {
             console.log("說話");
           };

優勢:代碼簡單。prototype

缺點: 建立多個對象會產生大量的代碼,編寫麻煩,且並無實例與原型的概念。設計

解決辦法:工廠模式。

二、工廠模式

概念 工廠模式是很是常見的一種設計模式,它抽象了建立具體對象的過程。JS 中建立一個函數,把建立新對象、添加對象屬性、返回對象的過程放到這個函數中,

用戶只需調用函數來生成對象而無需關注對象建立細節。

示例

function createObject(name,age) {
      this.name=name;
      this.age=age;
      this.say=function () {
        console.log("說話");
      };
    }
    var per1=createObject("張三",20);
    var per2=createObject("李四",30);

優勢:工廠模式解決了對象字面量建立對象代碼重複問題,建立類似對象可使用同一API。

缺點:由於是調用函建立對象,沒法識別對象的類型。

解決辦法:構造函數

三、構造函數

JS 中構造函數與其餘函數的惟一區別,就在於調用它的方式不一樣。任何函數,只要經過new 操做符來調用,那它就能夠做爲構造函數。

示例

//自定義構造函數----->實例化對象
    function Person(name,age,sex) {
      this.name=name;
      this.age=age;
      this.sex=sex;
      this.say=function () {
        console.log("說話");
      };
    }
    //構造函數---->建立對象
    var per1=new Person("張三",20,"女");
    var per2=new Person("李四",30,"女");

經過構造函數new一個實例經歷了四步:

1. 建立一個新對象;
2. 將構造函數內的 this 綁定到新對象上;
3. 爲新對象添加屬性和方法;
4. 返回新對象(JS 引擎會默認添加 return this;)。

而經過構造函數建立的對象都有一個constructor屬性,它是一個指向構造函數自己的指針,所以就能夠檢測對象的類型。

alert(per1.constructor === Person) //true
alert(per1 instanceof Person) // true

可是仍然存在問題:

alert(per1.say == per2.say) //false

同一個構造函數中定義了say(),而不一樣對象的同名函數倒是不相等的,意味着這兩個同名函數的內存空間不一致,也就是構造函數中的方法要在每一個實例上從新建立一次。

這顯然增長沒必要要內存空間。

優勢:解決了相似對象建立問題,且能夠檢測對象類型。

缺點:構造函數方法要在每一個實例上新建一次。

解決辦法:原型模式。


2、原型模式

一、概念

在JS中,建立對象的方式有工廠模式和構造函數模式等; 而構造函數模式最大的問題在於:構造函數中的每一個方法都須要在實例對象中從新建立一遍,不能複用

因此爲了解決這一個問題,就須要使用原型模式來建立對象。原型模式是把全部實例共享的方法和屬性放在一個叫作 prototype(原型)的屬性中 ,在建立一個函數

時都會有個prototype屬性, 這個屬性是一個指針,指向一個對象,是經過調用構造函數而建立的那個對象實例的原型對象。

若是你學習過java,咱們能夠簡單理解原型就比如咱們的靜態方法,任何對象均可以共享這個靜態方法。

做用 共享數據,節省內存空間。

二、舉例

使用原型,就意味着咱們能夠把但願實例共享的屬性和方法放到原型對象中去,而不是放在構造函數中,這樣每一次經過構造函數new一個實例,原型對象中定義

的方法都不會從新建立一次。

示例

//原型的做用之一:共享數據,節省內存空間
function Person() {
}
//經過構造函數的原型添加屬性和方法
Person.prototype.name = "張三";
Person.prototype.age = "20";
Person.prototype.say = function() {
  alert('經過原型建立吃飯方法');
};

var person1 = new Person();
var person2 = new Person();
alert(person1.name); //"張三"
alert(person2.name); //"張三"
alert(person1.say == person2.say); //true 經過原型建立的方法就爲true

優勢:與單純使用構造函數不同,原型對象中的方法不會在實例中從新建立一次,節約內存。

缺點:使用空構造函數,實例 person1 和 person2 的 name都同樣了,咱們顯然不但願全部實例屬性方法都同樣,它們仍是要有本身獨有的屬性方法。
而且若是原型中對象中有引用類型值,實例中得到的都是該值的引用,意味着一個實例修改了這個值,其餘實例中的值都會相應改變。

解決辦法:構造函數+原型模式組合使用。


3、構造函數+原型模式

最後一種方式就是組合使用構造函數和原型模式,構造函數用於定義實例屬性,而共享屬性和方法定義在原型對象中。這樣每一個實例都有本身獨有的屬性,

同時又有對共享方法的引用,節省內存。

//原型的做用之一:共享數據,節省內存空間
    //構造函數
    function Person(age,sex) {
      this.age=age;
      this.sex=sex;
    }
    //經過構造函數的原型添加一個方法
    Person.prototype.eat=function () {
      console.log("經過原型建立吃飯方法");
    };

    var per1=new Person(20,"男");
    var per2=new Person(20,"女");
    alert(per1.eat == per2.eat); //經過原型建立的方法就爲true

這種構造函數與原型模式混成的模式,是目前在 JS 中使用最爲普遍的一種建立對象的方法。


參考

一、JS面向對象編程之封裝 基本上參考這篇寫的,由於我認爲它寫的很是通俗易懂,不須要我再去整理了。很是感謝

二、js面向對象編程

三、JavaScript面向對象



別人罵我胖,我會生氣,由於我內心認可了我胖。別人說我矮,我就會以爲可笑,由於我內心知道我不可能矮。這就是咱們爲何會對別人的攻擊生氣。
攻我盾者,乃我心裏之矛(2)。
相關文章
相關標籤/搜索