あなたの知らないJavaScript-Intem 37は対象の高級なプログラムに向かって設計します.


1.JSは原型に基づくプログラムです.
簡単なオブジェクト指向クラスを作成します.属性があります.方法があります.
function Aaa(){
    this.name = '  ';
}
Aaa.prototype.showName = function(){
    alert( this.name );
};

var a1 = new Aaa();
a1.showName();
JS自身のオブジェクトの中でもnewオブジェクトであり、メソッドを呼び出します.
var arr = new Array();
arr.push();
arr.sort();
JSソースコード:システムオブジェクトもプロトタイプに基づいたプログラムです.たとえば:
function Array(){
    this.lenglth = 0;
}
Array.prototype.push = function(){};
Array.prototype.sort = function(){};
システムオブジェクトの下の方法や属性を変更したり、追加したりしないようにします.
var arr = [1,2,3];
Array.prototype.push = function(){}
arr.push(4,5,6);
alert( arr );
このように修正すると、プッシュ方法は無効になり、JS本省のプッシュ方法を覆っています.
では、どうやって自分でアラyのプッシュ方法を書き直しますか?
var arr = [1,2,3];
Array.prototype.push = function(){
    //this : 1,2,3
    //arguments : 4,5,6

    for(var i=0;ithis[this.length] = arguments[i]
    }

    return this.length;
};

arr.push(4,5,6);

alert( arr );*/

//pop shift unshift splice sort
2.JSの包装対象
私達はjsの基本的なデータのタイプがstring、number、bootlean、null、undefined、objectがあることを知っていますが、下のコードを見たら、何を発見しましたか?
var str = 'hello';

alert( typeof str );//String

str.charAt(0);
str.indexOf('e');
オブジェクト以外に方法を呼び出すことができますが、なぜ基本的なデータタイプが可能ですか?これはjsの中で、string、number、bootleanは自分の包装対象があるからです.Stering Number Boolean
var str = new String('hello');//                  ,         

//alert( typeof str );

alert(str.charAt(1));

String.prototype.charAt = function(){};
基本タイプの呼び出し方法では、何が起きましたか?
var str = 'hello';
str.charAt(0);  //                ,                     ,        ,           。
例えば文字列を実現するためのlastValueの方法です.
var str = 'hello';

String.prototype.lastValue = function(){
    return this.charAt(this.length-1);
};

alert( str.lastValue() ); //o
strは原型を通して継承して、自分にlastValue()の方法を持たせますので、直接に呼び出すことができます.例を見てみます.
var str = 'hello';

str.number = 10;

alert( str.number );  //undefined
ここはなぜundefinedですか?ここの包装のタイプはnumberをstrに共有していません.ただ自分で持っています.コピーして消えてしまいました.str.nameは値を受け取っていません.undefinedになります.
3.JSのプロトタイプチェーン
jsにおいて、インスタンスオブジェクトとプロトタイプの間の接続はプロトタイプチェーンと呼ばれ、プロトタイプチェーン間の接続は__proto__(暗黙的接続)と呼ばれている.
プロトタイプチェーンの最外層はObjectである.
function Aaa(){

}
Aaa.prototype.num = 10;
var a1 = new Aaa();
alert(a1.num);
例えば、私たちは一般的にオブジェクトAaaを定義し、プロトタイプにnumという属性を定義していますが、新newのa 1はどのようにプロトタイプの属性にアクセスしますか?
ここはa 1です.__proto__属性があります.Aaa.prototypeの原型オブジェクトを指しています.
もしそうなら
function Aaa(){
    this.num = 20;
}
Aaa.prototype.num = 10;
var a1 = new Aaa();
alert(a1.num);//20
ここにnumが二つありますが、どれが出ますか?これはプロトタイプチェーンの規則です.まず自分の対象から探して、自分の対象は原型の対象にならなかったです.....ずっと探していますが、どこが果てですか?objectのプロトタイプが見つかったら、エラーが発生します.objectのプロトタイプはnullです.このプロトタイプのチェーンはプロトタイプのチェーンです.例を見る
function Aaa(){
    //this.num = 20;
}
//Aaa.prototype.num = 10;
Object.prototype.num = 30;

var a1 = new Aaa();
alert(a1.num);
4.対象に向かういくつかの一般的な属性と方法
  • hasOwnProperty():対象自体の下の属性であるかどうかを見る
  • var arr = [];
    arr.num = 10;
    Array.prototype.num2 = 20;
    
    //alert(  arr.hasOwnProperty('num')  );  //true
    
    alert(  arr.hasOwnProperty('num2')  );  //false
  • constructor:オブジェクトの構造関数を見る
  • 各プロトタイプは、自動的にconstructor属性を追加します.
  • For inの場合、一部の属性は見つけられない
  • です.
  • construtor属性の変更を避ける
  • function Aaa(){
    }
    
    var a1 = new Aaa();
    
    alert( a1.constructor );  //Aaa
    
    var arr = [];
    alert( arr.constructor == Array );  //true
    各オブジェクトのプロトタイプの構造関数は自動的に自分を指し、他のものに変更できますが、変更は推奨されません.
    function Aaa(){
    }
    //Aaa.prototype.constructor = Aaa;   //         ,       
    
    //Aaa.prototype.constructor = Array;
    
    var a1 = new Aaa();
    alert( a1.hasOwnProperty == Object.prototype.hasOwnProperty );  //true
    
    ハスOwnProperty属性はプロトタイプチェーンを通してObject.prototypeのプロトタイプにあると説明します.
    時にはうっかりして原型を修正します.この時は原型を修正します.
    function Aaa(){
    }
    
    Aaa.prototype.name = '  ';//        ,constructor    
    Aaa.prototype.age = 20;
    
    Aaa.prototype = {//  json     ,        Object    ,  constructor   Object。
        constructor : Aaa,
        name : '  ',
        age : 20
    };
    
    var a1 = new Aaa();
    alert( a1.constructor );
    for inサイクルを採用していますが、原型のconstructor属性には循環しません.
    function Aaa(){
    }
    
    Aaa.prototype.name = 10;
    Aaa.prototype.constructor = Aaa;
    
    for( var attr in Aaa.prototype ){
        alert(attr);//  name
    }
  • instance of:演算子.オブジェクトと構造関数がプロトタイプチェーン上に関係していますか?
    function Aaa(){
    }
    
    var a1 = new Aaa();
    
    //alert( a1 instanceof Object );  //true
    
    
    var arr = [];
    
    alert( arr instanceof Array );//true;
  • toStering():システムオブジェクトの下にはすべて持参しています.自分の書いたオブジェクトはすべて原型チェーンを通してobjectの下を探しています.主にいくつかの解析を行い、主にAray、Boolean、Date、Object、Numberなどのオブジェクト
  • に用いられる.
    var arr = [];
    alert( arr.toString == Object.prototype.toString ); //false*/
    
    /*function Aaa(){
    }
    var a1 = new Aaa();
    alert( a1.toString == Object.prototype.toString );  //true*/
    -         
    
    /*var arr = [1,2,3];
    
        Array.prototype.toString = function(){
            return this.join('+');
        };
    
        alert( arr.toString() );  //'1+2+3'*/
  • 進数変換を行い、デフォルト10進数
  • //var num = 255;
        //alert( num.toString(16) );  //'ff'
  • 最も重要な点は、タイプ判断をすることです.
    //  toString       : 
    
    /*var arr = [];
    
    alert( Object.prototype.toString.call(arr) == '[object Array]' ); */ 
    //'[object Array]'
    タイプ判断の常用方法:三つのタイプのtypeofはだめです.全然区別がつかないです.データの種類を判断するなら、配列ですか?
    alert( arr.constructor == Array );  
    
    alert( arr instanceof Array );  
    
    alert( Object.prototype.toString.call(arr) == '[object Array]' ); 
    しかし、非常に特殊な場合には、三つ目しか使えません.iframeで一つの配列を作成すると、最初の二つの方法は無効になります.しかし、多くの場合はまだ大丈夫です.
    window.onload = function(){
    
        var oF = document.createElement('iframe');
        document.body.appendChild( oF );
    
        var ifArray = window.frames[0].Array;
    
        var arr = new ifArray();
    
        //alert( arr.constructor == Array );  //false
    
        //alert( arr instanceof Array );  //false
    
        alert( Object.prototype.toString.call(arr) == '[object Array]' );  //true   
    };
    5.JS対象の継承
    何が継承ですか既存のオブジェクトに基づいて、略して修正して、新しいオブジェクトが元のオブジェクトに影響しない機能を得る.
    その基本的な考え方は、原型を利用して、一つの引用タイプに別の引用タイプの属性と方法を継承させることです.
    コンストラクタ、プロトタイプ、およびインスタンスの関係:各コンストラクタにはプロトタイプオブジェクトがあり、プロトタイプオブジェクトはいずれもコンストラクタに向けられたポインタを含み、その例はプロトタイプオブジェクトに向けられた内部ポインタ_proto_を含む.
    1.原型継承
    プロトタイプチェーンを実現するには基本パターンがあります.そのコードは大体以下の通りです.
    function SuperType(){
        this.property = true;
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    };
    
    function SubType(){
        this.subproperty = false;
    }
    //   SuperType
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function (){
        return this.subproperty;
    };
    
    var instance = new SubType();
    alert(instance.getSuperValue()); //true
    以上のコードは二つのタイプを定義しています.SuperTypeとSubTypeです.各タイプにはそれぞれ属性と方法があります.これらの主な違いはSubTypeがSuperTypeを継承し、SuperTypeを作成し、SubType.prototypeにこのインスタンスを付与することによって達成される.実現の本質は元のオブジェクトを書き換えることであり、新しいタイプの実例を代用することである.言い換えれば、SuperTypeのインスタンスに元々存在していた全ての属性と方法は、現在もSubType.prototypeに存在している.継承関係を確立した後、SubType.prototypeに一つの方法を追加しました.このようにSuperTypeの属性と方法を継承した上で新しい方法を追加しました.この例の例と構造関数とプロトタイプの関係は図のようになっています.
    SubTypeのデフォルトで提供されたプロトタイプを使っていません.新しいプロトタイプに変えました.この新しい原型はスーパータイプの例です.このように、新しいプロトタイプは、SuperTypeの例として所有する属性と方法の全てだけでなく、その内部にはSuperTypeのプロトタイプを指すポインタがあります.
    すべての引用タイプはデフォルトでObjectを継承していますが、この継承もプロトタイプチェーンによって実現されています.上記の例で示したプロトタイプチェーンには他の継承レベルも含まれているはずです.
    プロトタイプおよびインスタンス間の関係instance ofオペレータ、isProttypeOf()方法は、2つの方法で決定され得る.
    alert(instance instanceof Object); //true
    alert(instance instanceof SuperType); //true
    alert(instance instanceof SubType); //true
    
    alert(Object.prototype.isPrototypeOf(instance)); //true
    alert(SuperType.prototype.isPrototypeOf(instance)); //true
    alert(SubType.prototype.isPrototypeOf(instance)); //true
    原型継承の注意点:
    (1)サブタイプは、親タイプのいずれかの方法を書き換える必要がある場合があります.または、超タイプの中には存在しない方法を追加する必要があります.いずれにしても、プロトタイプに方法を加えるコードは、プロトタイプを置き換える語句の後に必ず入れます.
    function SuperType(){
        this.property = true;
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    };
    function SubType(){
        this.subproperty = false;
    }
    //   SuperType
    SubType.prototype = new SuperType();
    //     ,          ,         。
    SubType.prototype.getSubValue = function (){
        return this.subproperty;
    };
        //         
        SubType.prototype.getSuperValue = function (){
            return false;
        };
        var instance = new SubType();
        alert(instance.getSuperValue()); //false
    (2)プロトタイプチェーンによる継承は、対象の字面量を用いてプロトタイプを作成することはできません.このようにするとプロトタイプチェーンを書き換えて、直接にJsonに取って代わられます.
    function SuperType(){
        this.property = true;
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    };
    function SubType(){
        this.subproperty = false;
    }
    //   SuperType
    SubType.prototype = new SuperType();
    //          ,          
    SubType.prototype = {
        getSubValue : function (){
            return this.subproperty;
        },
        someOtherMethod : function (){
            return false;
        }
    };
    var instance = new SubType();
    alert(instance.getSuperValue()); //error!
    プロトタイプチェーンの問題
    プロトタイプチェーンは強力ですが、それを使って継承が可能です.この中で、最も重要な問題は、引用型の値を含む原型から来ています.参照タイプの値を含むプロトタイプの属性は、すべてのインスタンスで共有されます.原型によって継承が実現されると、実際には別のタイプのインスタンスになります.したがって、元のインスタンスの属性は、現在のプロトタイプの属性になります.参照タイプはデータを共有します.
    function SuperType(){
        this.colors = ["red", "blue", "green"];
    }
    function SubType(){
    }
    //   SuperType
    SubType.prototype = new SuperType();
    
    var instance1 = new SubType();
    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    
    var instance2 = new SubType();
    alert(instance2.colors); //"red,blue,green,black"
    この例のSuperType構造関数は、1つの配列(参照タイプ値)を含むColors属性を定義している.SuperTypeの各例には、それぞれの配列を含むColors属性があります.SubTypeがプロトタイプチェーンを通してSuperTypeを継承した後、SubType.prototypeはSuperTypeの一例となったので、自分のcolors属性も持っています.SubType.prototype.com lors属性を専門に作成したのと同じです.しかし、結果は何ですか?その結果、SubTypeのすべてのインスタンスがこのColors属性を共有することになる.私たちはinstance 1.co lorsの修正がinstance 2.colorsを通じて反映されていることを十分に確認しました.
    プロトタイプチェーンの第二の問題は、サブタイプのインスタンスを作成する際に、超タイプの構造関数にパラメータを伝達できないことである.実際には、すべてのオブジェクトインスタンスに影響を与えずに、超タイプの構造関数にパラメータを伝達する方法がないというべきである.
    2.コンストラクタ継承(クラス相続)
    この技術の基本的な考えはかなり単純で,すなわちサブタイプのコンストラクタの内部で超タイプのコンストラクターを呼び出した.忘れないでください.関数は特定の環境でコードを実行する対象にすぎないので、appy()とcall()の方法を使うことによって(将来)新しく作成したオブジェクトにコンストラクターを実行することもできます.
    function SuperType(){
        this.colors = ["red", "blue", "green"];
    }
    function SubType(){
        //   SuperType
        SuperType.call(this);
    }
    var instance1 = new SubType();
    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    
    var instance2 = new SubType();
    alert(instance2.colors); //"red,blue,green"
    転送パラメータ
    プロトタイプ鎖に対して,借用構造関数は,サブタイプ構造関数において,超型構造関数にパラメータを伝達できる大きな利点がある.
    function SuperType(name){
        this.name = name;
    }
    function SubType(){
        //   SuperType,        
        SuperType.call(this, "Nicholas");
        //    
        this.age = 29;
    }
    
    var instance = new SubType();
    alert(instance.name); //"Nicholas";
    alert(instance.age); //29
    SubTypeコンストラクタ内部でSuperTypeコンストラクタを呼び出すと、実際にはSubTypeの例にname属性が設定されています.SuperTypeコンストラクタがサブタイプの属性を書き換えないようにするために、超タイプコンストラクタを呼び出した後、サブタイプで定義すべき属性を追加することができます.
    構造関数を借りる問題
    コンストラクタを借りるだけでは、コンストラクターモードの存在も回避できない問題になります.方法はコンストラクタで定義されていますので、関数多重化は説明できません.また、超タイプのプロトタイプで定義された方法は、サブタイプにとっても見られないものです.結果として、すべてのタイプはコンストラクターモードしか使用できません.
    3.コンビネーション引継ぎ
    プロトタイプチェーンと構造関数を借りる技術を一つのブロックに結合して、二つの長さの継承モードを発揮します.プロトタイプ鎖を用いてプロトタイプの属性と方法の継承を実現するという考えの背後にあるが、構造関数を借りることによってインスタンス属性の継承を実現する.このように、プロトタイプ上の定義方法によって関数多重が実現されるとともに、各インスタンスに独自の属性があることを保証することができる.
    function SuperType(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    SuperType.prototype.sayName = function(){
        alert(this.name);
    };
    
    function SubType(name, age){
        //    
        SuperType.call(this, name);
        this.age = age;
    }
    
    //    
    SubType.prototype = new SuperType();
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function(){
        alert(this.age);
    };
    
    var instance1 = new SubType("Nicholas", 29);
    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    instance1.sayName(); //"Nicholas";
    instance1.sayAge(); //29
    
    var instance2 = new SubType("Greg", 27);
    alert(instance2.colors); //"red,blue,green"
    instance2.sayName(); //"Greg";
    instance2.sayAge(); //27
    4.拡張:コピー引き継ぎ
    まず対象のコピーを理解してください.対象の引用は住所参照で、双方向変更です.基本的なデータタイプは値によって伝達され、元の値に影響を与えない.
    var a = {
        name : '  '
    };
    
    var b = a;
    
    b.name = '  ';
    
    alert( a.name );//  
    コピーして継承する方式を採用して、方法を一つ一つコピーしていけば、双方向継承が発生しなくなります.
    var a = {
        name : '  '
    };
    
    //var b = a;
    var b = {};
    extend( b , a );    
    b.name = '  ';
    alert( a.name );    
    
    function extend(obj1,obj2){
        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }
    このオブジェクトのコピーによって、コピーの継承が可能になります.
    //   :        ,              (      )
    
    //      :           call
    
    //      : for in :       (jquery        extend)
    
    function CreatePerson(name,sex){   //  
        this.name = name;
        this.sex = sex;
    }
    CreatePerson.prototype.showName = function(){
        alert( this.name );
    };
    
    var p1 = new CreatePerson('  ',' ');
    //p1.showName();
    
    
    function CreateStar(name,sex,job){  //  
    
        CreatePerson.call(this,name,sex);
    
        this.job = job;
    
    }
    
    //CreateStar.prototype = CreatePerson.prototype;
    
    extend( CreateStar.prototype , CreatePerson.prototype );
    
    CreateStar.prototype.showJob = function(){
    };
    
    var p2 = new CreateStar('   ',' ','  ');
    
    p2.showName();
    
    
    function extend(obj1,obj2){
        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }
    6.例:引継ぎでドラッグする
    
    <html>
    <head>
        <title>    title>
        <style type="text/css">
            #div1{width: 100px;height: 100px;background: red;position: absolute;}
            #div2{width: 100px;height: 100px;background: blue;position: absolute;left: 100px;}
        style>
    head>
    
    <body>
    <div id="div1">div>
    <div id="div2">div>
    
    
    <script type="text/javascript">
    
    window.onload = function(){
        var d1 = new Drag('div1');
        d1.init();
    
        var d2 = new childDrag('div2');
        d2.init();
    }
    
    
    function Drag(id){
        this.obj = document.getElementById(id);//       
        this.disX = 0;//    
        this.disY = 0;//    
    }
    
    Drag.prototype.init = function(){//    
        var that = this;
        this.obj.onmousedown = function(e){
            var e = e || window.event;
            that.fnDown(e);
    
            document.onmousemove = function(e){
                var e = e || window.evnet;
                that.fnMove(e);
            }
            document.onmouseup = function(){
                that.fnUP();
            }
            return false;
        }
    
    }
    
    Drag.prototype.fnDown = function(e){
        //clientX          ,         
        //offsetLeft:             
        this.disX = e.clientX - this.obj.offsetLeft;//     obj    
        this.disY = e.clientY - this.obj.offsetTop;
    }
    
    Drag.prototype.fnMove = function(e){
        this.obj.style.left = e.clientX - this.disX + 'px';
        this.obj.style.top = e.clientY - this.disY +'px';
    }
    
    Drag.prototype.fnUP = function(){
        document.onmousedown= null;
        document.onmousemove = null;
    }
    
    
    //    ,      ,        ,          
    
    function childDrag(id){
        Drag.call(this,id);//   call,apply
    }
    
    //    for in 
    extend(childDrag.prototype,Drag.prototype);
    
    //       
    childDrag.prototype.fnMove = function(e){
        var leftX = e.clientX - this.disX;
        var topY = e.clientY - this.disY;
        var clientW = document.documentElement.clientWidth - this.obj.offsetWidth;
        var clientH = document.documentElement.clientHeight  - this.obj.offsetHeight;
    
        if (leftX < 0){
            leftX = 0;
        }else if (leftX >clientW) {
            leftX = clientW;
        }
    
        if (topY < 0 ) {
            topY = 0;
        }else if (topY> clientH) {
            topY = clientH;
        }
    
        this.obj.style.left = leftX + 'px';
        this.obj.style.top = topY + 'px';
    }
    
    
    function extend(obj1, obj2){//    
        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }
    
    script>
    body>
    html>