<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # 原型與繼承 ## 原型與原型鏈 ![](https://box.kancloud.cn/967df0610cf32663d3680d30ca44685e_437x374.png) - `prototype`: 每個函數都有一個 prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,如果使用這個函數生成了實例,那么稱這個對象為所有實例的原型。 - `__proto__`: 每個對象都擁有`__proto__`屬性,該屬性用于實現原型鏈,當訪問一個對象的屬性時,如果該對象內部不存在這個屬性,就通過原型鏈找直到找到或者到終點 null。 - `constructor`:每個原型都有一個 constructor 屬性指向關聯的構造函數 ## Object() 與 Function() 所有的對象都是由 Object() 構造函數構造的,所有的函數聲明 / 函數表達式都是 Function() 構造函數的實例,而 Object() 構造函數本身又是 Function() 構造函數的實例,其原型關系如下: ![](https://img.kancloud.cn/a8/3a/a83aa3b28194c67d8076ed4a311471b5_610x507.png) 需要注意的是 Function() 的`__proto__ `屬性直接指向的是其原型對象。 我們可以用下面的代碼來驗證這張圖:在 node 環境及瀏覽器環境下都是一樣的結果 ```js console.log(Object.__proto__ === Function.prototype) // true console.log(Function.__proto__ === Function.prototype) // true console.log(Function.prototype.__proto__ === Object.prototype) // true console.log(Object.prototype.__proto__ === null) // true ``` ## 繼承 首先要理解構造函數 new 時執行了哪些操作 1. 創建一個新對象,并做原型綁定(該對象的 \_\_proto\_\_ 屬性指向構造函數的 prototype 屬性指向的對象) 2. 將 this 綁定到這個新對象上 3. 執行構造函數中的代碼(為這個新對象添加屬性) 4. 返回新對象(一般情況下,構造函數不返回值,但是用戶可以選擇主動返回對象,來覆蓋正常的對象創建步驟) 模擬實現 new ```js function _new (fn, ...args) { const obj = {} obj.__proto__ = fn.prototype fn.apply(obj, args) return Object.prototype.toString.call(obj) === '[object Object]' ? obj : {} } ``` ### 借用構造函數 在構造函數中使用 Parent.call(this) 的方法繼承父類屬性。 原理: 將子類的 this 使用父類的構造函數跑一遍 缺點: Parent 原型鏈上的屬性和方法并不會被子類繼承(子類連接不到父類) ``` javaScript function Parent () { this.name = 'parent' } Parent.prototype.sayHello = function () { console.log('say Hello') } function Child () { Parent.call(this) //函數名.call 調用這個函數但是更改其 this this.type = 'child' } let p1 = new Parent() let c1 = new Child() p1.sayHello() // 'say Hello' c1.sayHello() // error c1.sayHello is not a function ``` ### 原型鏈實現繼承 原理:把子類的 prototype(原型對象)直接設置為父類的實例 缺點:因為子類只進行一次原型更改,所以子類的所有實例保存的是同一個父類的值。 當子類對象上進行值修改時,如果是修改的原始類型的值,那么會在實例上新建這樣一個值; 但如果是引用類型的話,他就會去修改子類上唯一一個父類實例里面的這個引用類型,這會影響所有子類實例(一句話:子類修改原型上的引用類型會影響父類) ``` javaScript function Parent () { this.name = 'parent' this.arr = [1,2,3] } function Child () { this.type = 'child' } Child.prototype = new Parent() // 擁有了這個 Parent 實例上的屬性和方法 ``` 通過下面這個例子來觀察該方法的缺點 ``` function Parent () { this.names = ['kevin', 'daisy']; } function Child () { } Child.prototype = new Parent() var child1 = new Child() child1.names.push('yayu') console.log(child1.names) // ["kevin", "daisy", "yayu"] var child2 = new Child() console.log(child2.names) // ["kevin", "daisy", "yayu"] ``` ### 組合繼承方式(上面兩種方法的配合) 組合構造函數中使用 call 繼承和原型鏈繼承。 原理: 子類構造函數中使用 Parent.call(this) 的方式可以繼承寫在父類構造函數中 this 上綁定的各屬性和方法; 使用 Child.prototype = new Parent() 的方式可以繼承掛載在父類原型上的各屬性和方法 缺點: 父類構造函數在子類構造函數中執行了一次,在子類綁定原型時又執行了一次 ``` js function Parent () { this.name = 'parent' this.arr = [1,2,3] } function Child () { Parent.call(this) // 繼承 Parent 構造函數上的屬性和方法 this.type = 'child' } Child.prototype = new Parent(); // 繼承 Parent 的父類原型上的屬性和方法 ``` ### 組合繼承方式優化 使用 Object.create() 方法創建一個新對象,使用現有的對象(參數)來提供新創建的對象的 \_\_proto\_\_ ``` js function Parent () { this.name = 'parent' this.arr = [1,2,3] } function Child() { Parent.call(this) this.type = 'child' } Child.prototype = Object.create(Parent.prototype) // 提供__proto__ Child.prototype.constructor = Child ``` 這種方式也叫寄生組合式繼承,相比于之前的組合繼承方式,其減少了一次父類構造函數的調用,如果不使用 Object.create() 方法,有時候也會這么封裝: ```js function object (o) { function F() {} F.prototype = o return new F() } function prototype (child, parent) { var prototype = object(parent.prototype) prototype.constructor = child child.prototype = prototype } // 當我們使用的時候: prototype(Child, Parent) ``` ### ES6 實現繼承 ES6 的 Class 相當于構造函數的語法糖,extends 也是語法糖,其本質還是通過原型鏈實現繼承 ``` js // Extends 關鍵字配合 Class 實現繼承 class People { // 定義一個類 People constructor(name) { // constructor 函數,必須存在,接收實例化參數 this.name = name } getName() { console.log(this.name) // 類的屬性 } } class Student extends People { // Student 類繼承 People 類 constructor(name, grade) { // 聲明 constructor 方法 super(name) // 執行父類的構造函數 相當于 People.prototype.constructor.call(this) this.grade = grade } getGrade() { // Student 類的屬性 console.log(this.grade) } } let s = new Student('Tom', 6) // 實例化 Student 類 s.getName() // 調用繼承的屬性,輸出'Tom' s.getGrade() ``` ES5 的繼承實質是先創造子類的實例對象 this,然后再將父類的方法添加到 this 上面。ES6 的繼承機制是先創造父類的實例對象 this(所以必須先調用 super 方法),然后再將子類的構造函數修改 this ES5 的寄生組合式繼承: ```js function Parent (name) { this.name = name } function Child (name, age) { Parent.call(this, name) this.age = age } Child.prototype = Object.create(Parent.prototype) var child1 = new Child('kevin', '18') console.log(child1) ``` 對應的 ES6 的 class: ```js class Parent { constructor(name) { this.name = name } } class Child extends Parent { constructor(name, age) { super(name) // 調用父類的 constructor(name) this.age = age } } let child1 = new Child('kevin', '18') console.log(child1) ``` 對應的原型鏈示意圖為: <img src="https://box.kancloud.cn/b37f76b440aeb6b0bec9f8a7315fac55_584x497.png" />
                  <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>

                              哎呀哎呀视频在线观看