初めてextを知ってjsの潮流を理解します


冒頭、ネット上のExt-baseを大量に引用したいと思っていました.jsファイルの分析.しかし、海外の本を大量に読んだ結果、jsがオブジェクト向けのプログラミングとは何か分からなかった.
参考書:
Apress出版のPro.JavaScript.Design.Patterns
Professional.JavaScript.for.Web.Developers.2nd.Edition.2009
本文は一歩一歩javascript文法の進化を通じて最後に最もext-baseに達したいと思っている.jsの解析過程.
1.Javascriptのクラス
Javascriptの常識を利用して、jsの設計は以下のようにすべきだと思います.

/* Anim class. */
var Anim = function() {
...
};
Anim.prototype.start = function() {
...
};
Anim.prototype.stop = function() {
...
};
/* Usage. */
var myAnim = new Anim();
myAnim.start();
...
myAnim.stop();


新しいクラスAnimを定義し、prototypeプロパティに2つのメソッドを委任します.prototypeとは、私の理解はポインタです.実際にはc+,cにおけるポインタの動作方法とはわずかな違いがあるが,ほぼ同じである.詳しくは上の2冊の本を参考にしてください.
すべての属性と方法をクラスに入れるのが好きなら.次のようになります.

/* Anim class, with a slightly different syntax for declaring methods. */
var Anim = function() {
...
};
Anim.prototype = {
start: function() {
...
},
stop: function() {
...
}
};


以上の操作により,Encapsulationという新しい概念が生まれた.私の理解:箱詰め.すべてのプロパティとメソッドをクラスに配置します.
Javascriptの関数についてお話しします.javascriptでは関数がクラスです.
関数の大部分の概念はC++と何の違いもありません.匿名関数に注目してください.

<html>
    <head>
        <title>String Example</title>
        <script type="text/javascript">
        	// javascript ,        
			//         C++      。          
			//    :
            /* An anonymous function, executed immediately. */
            (function(){
                var foo = 10;
                var bar = 2;
                alert(foo * bar);
            })();
			//                    。   ()       。
			//     ,         
            /* An anonymous function with arguments. */
            (function(foo, bar){
                alert(foo * bar);
            })(10, 2);
			//          。             
            /* An anonymous function that returns a value. */
            var baz = (function(foo, bar){
                return foo * bar;
            })(10, 2);
            alert(baz);
			//               。
			//             ,                       。       
            /* An anonymous function used as a closure. */
            var baz;
            (function(){
                var foo = 10;
                var bar = 2;
                baz = function(){
                    return foo * bar;
                };
            })();
			baz(); // baz can access foo and bar, even though it is executed outside of the class
        </script>
    </head>
    <body>
        <!-- Nothing in the body -->
		// javascript ,        
			//         C++      。          
			//    :
            /* An anonymous function, executed immediately. */
            (function(){
                var foo = 10;
                var bar = 2;
                alert(foo * bar);
            })();
			//                    。   ()       。
			//     ,         
            /* An anonymous function with arguments. */
            (function(foo, bar){
                alert(foo * bar);
            })(10, 2);
			//          。             
            /* An anonymous function that returns a value. */
            var baz = (function(foo, bar){
                return foo * bar;
            })(10, 2);
            alert(baz);
			//               。
			//             ,                       。       
            /* An anonymous function used as a closure. */
            var baz;
            (function(){
                var foo = 10;
                var bar = 2;
                baz = function(){
                    return foo * bar;
                };
            })();
			baz(); // baz can access foo and bar, even though it is executed outside of the class
    </body>
</html>


箱詰めの書き方を使うなら、次のいずれかを試してみてください.

/* Add a method to the Function object that can be used to declare methods. */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
};
/* Anim class, with methods created using a convenience method. */
var Anim = function() {
...
};
Anim.method('start', function() {
...
});
Anim.method('stop', function() {
...
});
   method,               。      。
/* This version allows the calls to be chained. */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
return this;
};
/* Anim class, with methods created using a convenience method and chaining. */
var Anim = function() {
...
};
Anim.method('start', function() {
...
}).
method('stop', function() {
...
});

javascriptでは、すべてのものがオブジェクトであり、すべてのオブジェクトが可変です.これは、クラスを定義し、インスタンス化した後に変更できることを意味します.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
            // javascript ,         
            //          。
            //             ,         。
            /* Class Person. */
            function Person(name, age){
                this.name = name;
                this.age = age;
            }
            
            Person.prototype = {
                getName: function(){
                    return this.name;
                },
                getAge: function(){
                    return this.age;
                }
            }
            /* Instantiate the class. */
            var alice = new Person('Alice', 93);
            var bill = new Person('Bill', 30);
			document.write("/* Instantiate the class. */<br/>");
			document.write("name: "+alice.name+";her age: "+alice.age+"<br/>");
			document.write("name: "+bill.name+";his age: "+bill.age+"<br/>");
            /* Modify the class. */
            Person.prototype.getGreeting = function(){
                return 'Hi ' + this.getName() + '!';
            };
			document.write("/* Modify the class. */<br/>");
			document.write("alice.getGreeting:"+alice.getGreeting()+"<br/>");
            /* Modify a specific instance. */
            alice.displayGreeting = function(){
                alert(this.getGreeting());
            }
			document.write("/* Modify a specific instance.  */<br/>alert(getGreeting)");
			alice.displayGreeting();
			
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html>

このオブジェクトの可変性は自己検査introspectionと呼ばれます.任意の属性と方法をリアルタイムでチェックすることができます.これは、オブジェクトがリアルタイムで変更できるため、javascriptではタイプチェックが少ないためです.
javascriptには、まだ根強い概念があります.クローズクローズクローズ.閉パッケージはクラスで定義された関数です.オブジェクトに可変性があるため、クラスで定義された関数を予期せぬ呼び出しと変更できます.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
            function foo(){
                var a = 10;
                function bar(){
                    a *= 2;
                }
                bar();
                return a;
            }
            
            document.writeln(foo());
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

Javascriptで考えられるオブジェクトの作成スタイルは3種類あります.完全に表示されるオブジェクト(最も単純ですが、公開メンバーのみを指定します).カッコで識別する方法と属性を使用してプライベートメンバー(偽コードのみ)を区別します.詳細は上記の書籍を参照してください.最後に、パッケージを閉じる方法で本当のプライベートメンバーを作成します.パッケージを閉じることでプライベートメンバーを実現します.
閉パッケージの特性があれば、実際のプライベートメンバーとパブリックメンバーを実現することができます.Javascriptにはプライベート、公有の特性はありません.しかし、実際のプログラムでは、これらの特性を使用することが多い.これもオブジェクト向けの重要な部分の一つです.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
        var Book = function(newIsbn, newTitle, newAuthor){ // implements Publication
            // Private attributes.
            var isbn, title, author;
            
            // Privileged methods.
            this.getIsbn = function(){
                return isbn;
            };
            this.setIsbn = function(newIsbn){
                isbn = newIsbn;
            };
            this.getTitle = function(){
                return title;
            };
            this.setTitle = function(newTitle){
                title = newTitle || 'No title specified';
            };
            this.getAuthor = function(){
                return author;
            };
            this.setAuthor = function(newAuthor){
                author = newAuthor || 'No author specified';
            };
            // Constructor code.
            this.setIsbn(newIsbn);
            this.setTitle(newTitle);
            this.setAuthor(newAuthor);
        };
        // Public, non-privileged methods.
        Book.prototype = {
            display: function(){
                return "ISBN:"+this.getIsbn() + "<br/>"
				+"Title:" + this.getTitle() + "<br/>"
				+"Author:" + this.getAuthor();
            }
        };
		var book = new Book('978-0261103283','pro javascript design pattern','Apress');
		document.write(book.display());
		
		//        
		//     
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

しかし、このように書かれたクラスは、クラスメンバーを完成させたプライベートであり、公有的な特性である.しかし、このような方法は継承されにくく、メモリの冗長性も大量に発生します.javascriptにはリソース回収のメカニズムがないからです.クラスの使用が完了すると、ストレージスペースは消えません.静的方法と真の動的空間記憶方法も必要である.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
        var Book = (function(){
            // Private static attributes.
            var numOfBooks = 0;
            
            // Return the constructor.
            return function(newIsbn, newTitle, newAuthor){ // implements Publication
                // Private attributes.
                var isbn, title, author;
                // Private static method.
                function checkIsbn(isbn){
                    if (isbn) {
                        return true;
                    }
                    else {
                        return false;
                    }
                }
                // Privileged methods.
                this.getIsbn = function(){
                    return isbn;
                };
                this.setIsbn = function(newIsbn){
                    if (!checkIsbn(newIsbn)) 
                        throw new Error('Book: Invalid ISBN.');
                    isbn = newIsbn;
                };
                this.getTitle = function(){
                    return title;
                };
                this.setTitle = function(newTitle){
                    title = newTitle || 'No title specified';
                };
                this.getAuthor = function(){
                    return author;
                };
                this.setAuthor = function(newAuthor){
                    author = newAuthor || 'No author specified';
                };
                // Constructor code.
                numOfBooks++; // Keep track of how many Books have been instantiated
                // with the private static attribute.
                if (numOfBooks > 50) 
                    throw new Error('Book: Only 50 instances of Book can be ' +
                    'created.');
                this.setIsbn(newIsbn);
                this.setTitle(newTitle);
                this.setAuthor(newAuthor);
            }
        })();
        // Public static method.
        Book.convertToTitle = function(inputString){
            return inputString + "[us]";
        };
        // Public, non-privileged methods.
        Book.prototype = {
            display: function(){
                return "ISBN:" + this.getIsbn() + "<br/>" +
                "Title:" +
                this.getTitle() +
                "<br/>" +
                "Author:" +
                this.getAuthor();
            }
        };
        var book = new Book('978-0261103283', Book.convertToTitle('pro javascript design pattern'), 'Apress');
        document.write(book.display());
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

静的メソッドの実装は,実際には匿名関数を用いてメモリのスタックに空間を申請する.クラスには、この記憶領域のアドレスのみが記録されます.クラス呼び出しが完了すると、匿名関数は消えます.同時にクラスで申請された静的変数が保持されます.
上のオブジェクト向けの公有私有メンバーと方法,オブジェクト可変性の概念がある.jsで継承された実装を見てみましょう
Javascriptの構文は、オブジェクトベースの継承を使用することを提供します.クラスベースの継承をシミュレートするために使用できます.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
            /* Class Person. */
            function Person(name){
                this.name = name;
            }
            
            Person.prototype.getName = function(){
                return this.name;
            }
            /* Class Author. */
			//     ,      
            function Author(name, books){
			//  ,       ,call       ,    	
                Person.call(this, name); // Call the superclass's constructor in the scope of this.
                this.books = books; // Add an attribute to Author.
            }
            //    new   ,          。      object      。
			//           scope chain
            Author.prototype = new Person(); // Set up the prototype chain.
            Author.prototype.constructor = Author; // Set the constructor attribute to Author.
            Author.prototype.getBooks = function(){ // Add a method to Author.
                return this.books;
            };
            
            //    
            var author = [];
            author[0] = new Author('Dustin Diaz', ['JavaScript Design Patterns']);
            author[1] = new Author('Ross Harmes', ['JavaScript Design Patterns']);
            
            document.write(author[0].getName()+' ' +author[0].getBooks()+"<br/>");
			document.write(author[1].getName()+' ' +author[1].getBooks());
			
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

コードはかなり簡単ですが、prototypeというポインタを利用してアドレスのリンクを行います.しかし、それは複雑な話題です.JAvascriptはキーワードを継承していません.代わりに、各objectオブジェクトにはprototypeプロパティがあります.このプロパティは、別のオブジェクトまたはnullを指します.オブジェクトメンバーが読み込まれるとjavascriptはprototypeでオブジェクトを読み込みます.現在のオブジェクトに存在しない場合、javascriptは各オブジェクトのprototypeを読み込みます.オブジェクトまたはnullが読み出されるまで、他のオブジェクト向け言語とはまったく異なります.この方法は,複数のサブクラスをインスタンス化するとともに,親クラスも同様に何度もインスタンス化する.メモリを無駄にしました.子クラスがインスタンス化されている場合、インスタンス化は親クラスを変更し、子クラスに大きな影響を与えます.
以上の理由から,継承の仕方を変更しなければならない.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
            /* Extend function, improved. */
            function extend(subClass, superClass){
                var F = function(){
                };
                F.prototype = superClass.prototype;
                subClass.prototype = new F();
                subClass.prototype.constructor = subClass;
                subClass.superclass = superClass.prototype;
                if (superClass.prototype.constructor == Object.prototype.constructor) {
                    superClass.prototype.constructor = superClass;
                }
            }
            
            /* Class Person. */
            function Person(name){
                this.name = name;
            }
            
            Person.prototype.getName = function(){
                return this.name;
            }
            /* Class Author. */
            function Author(name, books){
                Author.superclass.constructor.call(this, name);
                this.books = books;
            }
            
            extend(Author, Person);
            Author.prototype.getBooks = function(){
                return this.books;
            };
            //  Author 
            Author.prototype.getName = function(){
                var name = Author.superclass.getName.call(this);
                return name + ', Author of ' + this.getBooks().join(', ');
            };
            
            //    
            var author = [];
            author[0] = new Author('Dustin Diaz', ['JavaScript Design Patterns']);
            author[1] = new Author('Ross Harmes', ['JavaScript Design Patterns']);
            
            document.write(author[0].getName() + "<br/>");
            document.write(author[1].getName());
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

継承方式はすでに実現されている.でもext-base.jsの目標はまだ遠い.ここで、まず一つの概念を提出します:Prototypal Inheritance、私の理解は:ポインタ型継承.ポインタ型継承は非常に異なります.クラスとインスタンス化に関するすべての方法を忘れることが最善の方法であることを発見しました.オブジェクト自体のみを考慮し、典型的にオブジェクトを作成するには2つの方法があります.
a.オブジェクト構造の定義、クラス宣言の使用
b.クラスをインスタンス化し、オブジェクトを作成する(ネット上ではオブジェクト直接量と呼ぶ)
インスタンス化クラスによって作成されるオブジェクトは、すべてのインスタンス化されたプロパティをコピーし、すべてのインスタンス化メソッドのアドレスをポインタ型継承に接続する利点があります.これにより、簡単にクラスを構築できるという利点があります.このクラスは他のクラスで再利用できます.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
			//           
            /* Clone function. */
            function clone(object){
                function F(){
                }
                F.prototype = object;
                return new F;
            }
            
            /*
             *      Prototypal Inheritance
             *          。                             。       
             *            
             * a.      ,     
             * b.    ,     
             *                        ,            
             *        ,          。           
             */
            /* Person Prototype Object. */
            var Person = {
                name: 'default name',
                getName: function(){
                    return this.name;
                }
            };
            //          
            var reader = clone(Person);
			document.write("<h5 style='color:red'>simple object inherited and testing</h5>");
            document.write(reader.getName() + "<br/>"); // This will output 'default name'.
            reader.name = 'John Smith';
            document.write(reader.getName() + "<br/>"); // This will now output 'John Smith'.
            
			
            /* Author Prototype Object. */
            var Author = clone(Person);
            Author.books = []; // Default value.
            Author.getBooks = function(){
                return this.books;
            }
            
            var author = [];
            author[0] = clone(Author);
            author[0].name = 'Dustin Diaz';
            author[0].books = ['JavaScript Design Patterns'];
            author[1] = clone(Author);
            author[1].name = 'Ross Harmes';
            author[1].books = ['JavaScript Design Patterns'];
			document.write("<h5 style='color:red'>Author object inherited and testing</h5>");
            document.write(author[0].getName() + ' ' + author[0].getBooks() + "<br/>");
            document.write(author[1].getName() + ' ' + author[1].getBooks() + "<br/>");
            
            /*
             *         
             *             ,               。            。
             *        ,  Author     books  。     author[1].books.push('New Book Title')     
             *              。  prototype     
             * clone     object   prototype       。
             *     author[1].name,      prototype       。         
             *      author[1].name,    author[1]           
             */
            var authorClone = clone(Author);
			document.write("<h5 style='color:red'>Symmetrical Reading and Writing of Inherited Members</h5>");
            document.write("Name="+authorClone.getName() + "<br/>"); // Linked to the primative Person.name, which is the string 'default name'.
            document.write("Books="+authorClone.getBooks() + "<br/>");
            authorClone.name = 'new name'; // A new primative is created and added to the
            // authorClone object itself.
            document.write("Name="+authorClone.getName() + "<br/>"); // Now linked to the primative authorClone.name, which
            // is the string 'new name'.
            authorClone.books.push('new book'); // authorClone.books is linked to the array
            document.write("Books="+authorClone.getBooks() + "<br/>");
            // Author.books. We just modified the
            // prototype object's default value, and all
            // other objects that link to it will now
            // have a new default value there.
            authorClone.books = []; // A new array is created and added to the authorClone
            // object itself.
            authorClone.books.push('a new book to array'); // We are now modifying that new array.
            document.write("<h5 style='color:red'>Asymmetrical Reading and Writing of Inherited Members</h5>");
            document.write(authorClone.getName() + ' ' + authorClone.getBooks() + "<br/>");
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

Prototypal Inheritanceのポインタ継承により,スケルトンモードという設計モードを体得した.スケルトンモードとは、ベースクラスがすべてのプロパティとメソッドを設定し、デフォルト値を付与することです.サブクラスは任意に追加できる独自の方法が必要です.ここでは、親メンバーを非同期で読み書きする概念を示します.ポインタ型継承を有効に使用するためには、伝統的な継承方法をすべて忘れなければなりません.これが忘れなければならない方法の一つです.従来の継承では、Authorクラスごとにbooks配列がコピーされています.author[1]を通じてbooks.Push('New Book Title')を配列に追加します.この方式はポインタ型継承には使用できません.prototypeチェーンが効いたからです.clone関数はobjectオブジェクトのprototypeが完全に独立したコピーではありません.author[1]を読むとname、prototypeから保存された接続を得るだけです.インスタンスの値は得られませんでした.authorを書くとnameは、実際にauthor[1]オブジェクトに新しい属性を追加します.通俗的に言えば、父類は骨格を与え、子類は肉を加えた.
ただし、ポインタオブジェクトにはサブオブジェクトが含まれている場合があります.サブオブジェクトの単一のメソッドを書き換えるには、オブジェクト全体を再構築する必要があります.これは、サブオブジェクトを空のオブジェクトにコピーすることによって実現できます.ただし、クローンされたオブジェクトは、サブオブジェクトの構造とデフォルト値を明確にする必要があります.各オブジェクト間の低結合度を維持するには、複雑なサブオブジェクトは固定された方法で作成する必要があります.工場モデルが生成されます.
<html> 
    <head> 
        <title>String Example</title> 
        <script type="text/javascript"> 
            /* Clone function. */
            function clone(object){
                function F(){
                }
                F.prototype = object;
                return new F;
            }
            
            /*
             *    ,             。
             *                  ,         
             *                  
             *                          
             *               ,                   
             *          
             */
            var CompoundObject = {};
            CompoundObject.string1 = 'default value';
            CompoundObject.createChildObject = function(){
                return {
                    bool: true,
                    num: 10
                }
            };
            CompoundObject.childObject = CompoundObject.createChildObject();
            var compoundObjectClone = clone(CompoundObject);
            compoundObjectClone.childObject = CompoundObject.createChildObject();
            compoundObjectClone.childObject.num = 5;
			document.write(compoundObjectClone.string1 + "<br/>");
			document.write(compoundObjectClone.childObject.num);
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html> 

これでext-base.jsのすべての概念があります.次にextendクラスの具体的な分析を開始します
<html> 
    <head> 
        <title>Extend Example</title> 
        <script type="text/javascript"> 
        	//Ext         
			//    。  Prototypal Inheritance       
        	//ext                 。
            Ext = {
                version: '3.0'
            };
			//Ext        。              。
			/*
			 * in      IE          
			 *        toString(),hasOwnProperty() ,propertyIsEnumerable() , toLocaleString() , valueOf()
			 * Ext       overrides    apply    ,    toString      object      。
			 * apply      applyif。         ,      。
			 */
            Ext.apply = function(o, c, defaults){
                // no "this" reference for friendly out of scope calls
                if (defaults) {
                    Ext.apply(o, defaults);
                }
                if (o && c && typeof c == 'object') {
                    for (var p in c) {
                        o[p] = c[p];
                    }
                }
                return o;
            };
            Ext.apply(Ext, {
				//    v   object 
                isObject: function(v){
                    return v && typeof v == "object";
                },
				//Ext      
				/*
				 *   :
				 * 1、              -       ,       。
				 * 2、              ,           。
				 */
				//Ext      
                extend: function(){
                    // inline overrides
					//       supperclass,subclass,overrides     io   。
					
                    var io = function(o){
                        for (var m in o) {
                            this[m] = o[m];
                        }
                    };
                    var oc = Object.prototype.constructor;
                    
                    return function(sb, sp, overrides){
					//             object。
					//     overrides ,  overrides    constructor  ,
					//  overrides constructor         。
					//  ,     function,       ,  "sp.apply(this, arguments);",
					//           ,   extend             sp     。
					//      
                        if (Ext.isObject(sp)) {
                            overrides = sp;
                            sp = sb;
                            sb = overrides.constructor != oc ? overrides.constructor : function(){
                                sp.apply(this, arguments);
                            };
                        }
						//var F=function(){},       ,      。
						//F.prototype=sp.prototype
						//sbp=new F() F.prototype   sp.prototype        sb.prototype
						//  ,  F           ,      delete    。
						//       sbp。
						//      ,                ,      
                        var F = function(){
                        }, sbp, spp = sp.prototype;
                        
                        F.prototype = spp;
                        sbp = sb.prototype = new F();
						//sb.prototype.constructor F(),  sbp.constructor=sb
                        sbp.constructor = sb;
                        sb.superclass = spp;
                        if (spp.constructor == oc) {
                            spp.constructor = sp;
                        }
                        sb.override = function(o){
                            Ext.override(sb, o);
                        };
                        sbp.superclass = sbp.supr = (function(){
                            return spp;
                        });
                        sbp.override = io;
                        Ext.override(sb, overrides);
                        sb.extend = function(o){
                            Ext.extend(sb, o);
                        };
                        return sb;
                    };
                }(),
				// apply     ,    。       toString,     。
                override: function(origclass, overrides){
                    if (overrides) {
                        var p = origclass.prototype;
                        Ext.apply(p, overrides);
                        if (Ext.isIE && overrides.toString != origclass.toString) {
                            p.toString = overrides.toString;
                        }
                    }
                }
            });
			//    
			//       S
            function S(){
            }
            //S     s,s1
            S.prototype.s = "s";
            S.prototype.s1 = "s1";
			//     C
			//C     c,c1
            function C(){
                this.c = "c";
                this.c1 = "c1";
            }
            //C  S  ,   s1
            Ext.extend(C, S, {
                s1: "by c overload"
            });
			//   C
            var c = new C();
            alert(c.s); //s   
            alert(c.s1); //by c overload 
        </script> 
    </head> 
    <body> 
        <!-- Nothing in the body --> 
    </body> 
</html>