JavaScript自定義“類”庫

 

JavaScript 是基於原型的語言,在es6 之前並沒有包含內置類的實現。但是這並不意味着類在JavaScript中毫無必要 。實際上類是一種很有用的工具,像其他編程語言中一樣,類在JavaScript中同樣可以起到重要的作用 。

 

下面我們手動封裝一個類庫,實現一個簡單的類的創建。

預期實現的功能:

1.   可以對新創建出來的類進行初始化

2.   可以擴展類的靜態屬性與方法

3.   可以擴展類的實例的屬性與方法

4.   在創建類時可以繼承其他類的屬性與方法。

代碼實現:

varClass=function (parent) {

    // 初始化類庫

    var _class =function () {

        this.init.apply(this,arguments); //將原型init方法上的屬性同步到當前類

    }

    _class.prototype.init=function () { }

 

    // 動態擴展

 

    // 定義別名

    _class.fn=_class.prototype;

 

    _class.fn.parent=_class;

 

    // 給類添加屬性和方法

 

    _class.extend=function (obj) {

        var extended = obj.extended;

        for(var i in obj)

        {

            _class[i] = obj[i]

        }

        if(extended) extended(_class); //回調,用於類自身擴展成功後的提示

    }

 

    // 給類的實例添加屬性和方法

 

    _class.include=function (obj) {

         var included = obj.included;

         for(var i in obj)

         {

             _class.fn[i]=obj[i];

         }

         if(included) included(_class);// 回調,用於類實例擴展後的提示

    }

 

        // 給類添加繼承

          if(parent)

          {

              var subclass=function () { };

              subclass.prototype =parent.prototype;

              _class.prototype = new subclass;

          }

 

      return _class;

 

}

 

// 使用“類”庫

        var Cat = new Class();

 

        Cat.prototype.init=function(name,color) { // 對類進行初始化,修改爲帶有參數的類

            this.name = name;

            this.color = color;

            this.like = function () {

                return "fish";

            }

        }

        var cat = new Cat("mini","yellow");

        console.log( cat.name + " is"+ cat.color + " it like "+ cat.like());

 

           var Animal = new Class();

           Animal.prototype.init=function () {

                this.feed = "nurse";// 動物的餵養方式是哺乳

           }

 

           Animal.extend({  // 擴展類的靜態屬性和方法

                extended:function (_class){  //設置回調函數,用於擴展成功後的顯示

                    console.log(_class+"is extended");

                },

                ClassName:"Animal"

           })

 

            Animal.include({ // 擴展類實例的屬性和方法

               walk:"crawl",

               birth:function () {

               console.log("胎生哺乳");

            }})

 

           console.log(Animal.ClassName);

           var Dog = new Class(Animal);

           var dog = new Dog();

           console.log(dog.feed);

           console.log(dog.walk);

 

在開始分析上邊的代碼之前先和大家討論一下原型的概念,關於原型有幾個重要的點是我們需要了解的:

1.   我們將原型也稱爲“模板對象”,它上邊的屬性用來初始化一個新對象 。

2.   任何對象都可以作爲另一個對象的原型對象,以此來實現屬性共享 。

3.   我們也可以將原型理解爲某種形式的繼承。

代碼詳解:

首先因爲我們的最終目的是想通過 Class函數 ,返回給我們一個構造函數 用於表示我們新創建的類 。所以只需要在Class 函數定義另一個構造函數(_class ),最終將其返回出來就好了。

在函數_class 的原型上定義一個init方法,並運用apply方法使_class繼承自身prototype.init 方法。這樣,當我們在新類的prototype.init 方法上進行初始化設置時,就會將內容同步到當前的類中。

關於屬性和方法的擴展 。當我們要擴展的是類的靜態屬性和方法,只需要將傳入的對象上的屬性都複製到當前對象就可以了 。而如果我們需要對當前類的實例也進行屬性和方法的擴展,就需要將傳入的對象上的屬性都複製到當前類的原型上 。 當然在這裏我們加了一個回調函數的功能,用於擴展成功後的顯示 (實際上如果你不能很好地理解,去除這一部分同樣是可以的)。

給“類”庫添加繼承,我們傳入的參數是一個可選的父類。注意如果將parent直接傳入Class構造函數則所有子類都必然共享一個原型,這不是我們想要的結果。當然也不可以直接將parent的prototype與_class的prototype進行綁定,因爲一旦這樣做了,任何一方發生改變,另一個也將隨之發生改變,這同樣不是我們想要的結果。這裏還有非常重要的一點需要我們記住:只有實例的屬性纔會被繼承 。在這裏我們通過創建匿名函數的小技巧,避免了在繼承parent類的時候創建parent類的實例 。

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章