<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## JS實現繼承的6種方式 JavaScript實現繼承的6種方式 **1 、原型鏈繼承** 將構造函數的原型設置為另一個構造函數的實例對象,這樣就可以繼承另一個原型對象的所有屬性和方法,可以繼續往上,最終形成原型鏈。 第一個問題是,當實現繼承后,另一個原型的實例屬性,變成了現在這個原型的原型屬性,然后該原型的引用類型屬性會被所有的實例共享,這樣繼承原型引用類型屬性的實例之間不再具有自己的獨特性了。 第二個問題是,在創建子類型的實例時,沒有辦法在不影響所有對象實例的情況下給超類型的構造函數中傳遞參數。 **2、借用構造函數繼承** 為了解決原型中包含引用類型值的問題,開始使用借用構造函數,也叫偽造對象或經典繼承 ~~~ 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" ~~~ 將SuperType函數在SubType構造函數中調用,在每個實例中執行,這樣每個實例中都會有一份SuperType中的屬性方法的副本,也就實現了繼承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 ~~~ 將SubType的原型指定為SuperType的一個實例,大致步驟和原型鏈繼承類似,只是多了在SubType中借調SuperType的過程。 實例屬性定義在構造函數中,而方法則定義在構造函數的新原型中,同時將新原型的constructor指向構造函數。 可以通過instanceof和isPrototypeOf()來識別基于組合繼承創建的對象。 避免了原型鏈和借用構造函數的缺陷,融合了它們的優點,成為JS中最常用的繼承模式。 實際上是借用了構造函數,以覆蓋的方式,解決了在原型鏈繼承中原型的引用類型屬性共享在所有實例中的問題。 因為在子類型中借調構造函數(SuperType.call(this))時,會在自己的所有實例中執行一遍SuperType中的代碼,由于每個實例this都是不同的,因此SuperType中定義的屬性會在每個實例中有一份副本,也就避免了原型鏈繼承中,原型屬性共享的問題(覆蓋了原型屬性)。 **4.、原型式繼承** 不自定義類型的情況下,臨時創建一個構造函數,借助已有的對象作為臨時構造函數的原型,然后在此基礎實例化對象,并返回。 ~~~ function object(o){ function F(){} F.prototype = o; return new F(); ~~~ 本質上是object()對傳入其中的對象執行了一次淺復制 ~~~ var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie" ~~~ 原型的引用類型屬性會在各實例之間共享。 當只想單純地讓一個對象與另一個對象保持類似的情況下,原型式繼承是完全可以勝任的。 注意: ES5 通過新增 Object.create()方法規范化了原型式繼承。這個方法接收兩個參數:一個用作新對象原型的對象和(可選的)一個為新對象定義額外屬性的對象。在傳入一個參數的情況下,Object.create()與這里的object()方法的行為相同。第二個參數與Object.defineProperties()方法的第二個參數格式相同:每個屬性都是通過自己的描述符定義的。 **5、寄生式繼承** 其實就是在原型式繼承得到對象的基礎上,在內部再以某種方式來增強對象,然后返回。 ~~~ function createAnother(original) { var clone = object(original); clone.sayHi = function() { alert("hi"); }; return clone; } ~~~ 思路與寄生構造函數和工廠模式類似。 新的對象中不僅具有original的所有屬性和方法,而且還有自己的sayHi()方法。 寄生式繼承在主要考慮對象而不是自定義類型和構造函數的情況下非常有用。 由于寄生式繼承為對象添加函數不能做到函數復用,因此效率降低。 **6、寄生組合式繼承** 組合繼承是JS中最常用的繼承模式,但其實它也有不足,組合繼承無論什么情況下都會調用兩次超類型的構造函數,并且創建的每個實例中都要屏蔽超類型對象的所有實例屬性。 寄生組合式繼承就解決了上述問題,被認為是最理想的繼承范式。 ~~~ function object(o) { function F(){} F.prototype = o; return new F(); } function inheritPrototype(superType, subType) { var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; } 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; } inheritPrototype(SuperType, SubType); // 這一句,替代了組合繼承中的SubType.prototype = new SuperType() SubType.prototype.sayAge = function() { alert(this.age); }; ~~~ 既然在組合模式中我們通過借調構造函數來為每個實例定義實例屬性,從而覆蓋原型屬性,影響了效率,那么是否可以把原型改變一下呢,不讓它作為SuperType的實例,這樣就不會有一些無用的原型屬性了。 不必為了指定子類型的原型而調用超類型的構造函數,我們需要的只不過是超類型原型的一個副本。 在inheritPrototype()函數中所做的事: 在inheritPrototype函數中用到了原型式繼承中的object()方法,將超類型的原型指定為一個臨時的空構造函數的原型,并返回構造函數的實例。 此時由于構造函數內部為空(不像SuperType里面有實例屬性),所以返回的實例也不會自帶實例屬性,這很重要!因為后面用它作為SubType的原型時,就不會產生無用的原型屬性了,借調構造函數也就不用進行所謂的“重寫”了。 然后為這個對象重新指定constructor為SubType,并將其賦值給SubType的原型。這樣,就達到了將超類型構造函數的實例作為子類型原型的目的,同時沒有一些從SuperType繼承過來的無用原型屬性。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看