JavaScript継承の詳細(一)


オブジェクト向けとオブジェクトベース
ほとんどの開発者がオブジェクト向け言語を持っています(C++、C#、Javaなど)の開発経験があります.従来のオブジェクト向け言語では、2つの非常に重要な概念-クラスとインスタンスがあります.クラスは物事の共通の行為と方法を定義し、インスタンスはクラスの具体的な実現です.オブジェクト向けプロセスには3つの重要な概念-パッケージ、継承、マルチステートがあることも知っています.
しかしJavaScriptの世界では、これらのすべての特性は存在しないようです.JavaScript自体はオブジェクト向けの言語ではなく、オブジェクトベースの言語だからです.JavaScriptのすべてのものがオブジェクトであり、文字列、配列、日付、数字、さらには関数など、興味深い特性があります.例えば、次の例です.
    //        - add
    function add(a, b) {
        add.invokeTimes++;
        return a + b;
    }
    //           ,     add      ,             
    add.invokeTimes = 0;
    add(1 + 1);
    add(2 + 3);
    console.log(add.invokeTimes); // 2
    

 
JavaScriptでのクラスと継承のシミュレーション
オブジェクト向け言語では、クラスを使用してカスタムオブジェクトを作成します.しかし、JavaScriptではすべてのものがオブジェクトですが、カスタムオブジェクトを作成するにはどのような方法がありますか?
これはもう一つの概念-プロトタイプ(prototype)を導入する必要があります.私たちは簡単にprototypeをテンプレートと見なすことができます.新しく作成されたカスタムオブジェクトはすべてこのテンプレート(prototype)のコピーです(実際にはコピーではなくリンクですが、このリンクは見えません.コピーのような感じがします).
prototypeでカスタムオブジェクトを作成する例を見てみましょう.
 //     
    function Person(name, sex) {
        this.name = name;
        this.sex = sex;
    }
    //   Person   ,                
    Person.prototype = {
        getName: function() {
            return this.name;
        },
        getSex: function() {
            return this.sex;
        }
    }
    

ここでは,関数Personをコンストラクション関数,すなわちカスタムオブジェクトを作成する関数と呼ぶ.JavaScriptは,構築関数とプロトタイプのシミュレーションによりクラスの機能を実現していることが分かる.カスタムオブジェクト(インスタンス化クラス)のコードを作成するには:
 
    var zhang = new Person("ZhangSan", "man");
    console.log(zhang.getName()); // "ZhangSan"
    var chun = new Person("ChunHua", "woman");
    console.log(chun.getName()); // "ChunHua"
    

コードvar zhang=new Person("ZhangSan","man")が実行されると、内部では次のようなことが行われます.
  • 空白オブジェクト(new Object()を作成します.
  • コピーPerson.prototypeのプロパティ(キー値ペア)は、この空のオブジェクトに挿入されます(前述したように、内部実装ではコピーではなく非表示のリンクです).
  • このオブジェクトをthisキーワードを介してコンストラクション関数に渡し、コンストラクション関数を実行します.
  • このオブジェクトを変数zhangに割り当てます.

  •  
    prototypeテンプレートがインスタンス化されたオブジェクトにコピーされていないことを証明するために、次のコードを参照してください.
     
        function Person(name, sex) {
            this.name = name;
            this.sex = sex;
        }
        Person.prototype.age = 20;
        var zhang = new Person("ZhangSan", "man");
        console.log(zhang.age); // 20
        //   prototype  age  
        zhang.age = 19;
        console.log(zhang.age); // 19
        delete zhang.age;
        //        age ,      prototype   
        console.log(zhang.age); // 20
        

    このJavaScript内部で実装される隠れたprototypeリンクは,JavaScriptが生存に頼る温潤な土壌であり,シミュレーション実装継承の基礎でもある.
     
    JavaScriptで簡単な継承を実現するにはどうすればいいですか?次の例では、Personからプロトタイプprototypeのすべてのプロパティを継承する従業員クラスEmployeeを作成します.
     
        function Employee(name, sex, employeeID) {
            this.name = name;
            this.sex = sex;
            this.employeeID = employeeID;
        }
        //  Employee     Person     
        //   Person       Person      ,   Employee        Person        。
        Employee.prototype = new Person();
        Employee.prototype.getEmployeeID = function() {
            return this.employeeID;
        };
        var zhang = new Employee("ZhangSan", "man", "1234");
        console.log(zhang.getName()); // "ZhangSan
        

     
    継承の実装は粗く、多くの問題があります.
  • Employeeコンストラクタとプロトタイプ(以降クラスと略す)を作成する際にPersonをインスタンス化したのは不適切です.
  • Employeeのコンストラクション関数では親Personのコンストラクション関数を呼び出すことができず、Employeeコンストラクション関数ではnameとsex属性の重複割り当てが発生します.
  • Employeeの関数はPersonの同じ名前の関数を上書きし、リロードのメカニズムはありません(前のものと同じタイプの問題です).
  • JavaScriptクラスを作成する構文はばらばらすぎて、C#/Javaの構文ほど優雅ではありません.
  • 実装にはconstructorプロパティの指向エラーがあり、これは2番目の記事で議論されます.

  • 私たちは第3章でこの例を改善します.
     
    JavaScript継承の実装
    JavaScript自体には完全なクラスと継承の実装がなく、手作業で実装する方法にも多くの問題があるため、この挑戦的なタスクネットワークには多くの実装があります.
  • Douglas Crockford - Prototypal Inheritance in JavaScript
  • Douglas Crockford - Classical Inheritance in JavaScript
  • John Resig - Simple JavaScript Inheritance
  • Dean Edwards - A Base Class for JavaScript Inheritance
  • Prototype
  • Mootools
  • Extjs

  • このシリーズの文章はこれらの実装を一つ一つ深く分析し、最終的にJavaScriptでどのようにクラスを実装し、継承するかを深く理解します.
     
    次の章では、this、constructor、prototypeなど、クラス実装に関する知識について説明します.