zoukankan      html  css  js  c++  java
  • js原型鏈與js繼承解析

    最近在網上看了諸多js原型鏈的解析,說得雲裡霧裡,不明所以。徹底了解後,決定出個博客記錄一下,一是方便後來人學習,二是方便日後複習。

    首先,我們來看一下構造函數、原型、實例之間的關係圖:

    所以,我們通常所說的原型鏈,其實指的就是  prototype 的鏈路,因為構造函數和實例是沒有任何指向父節點的成員的。

    我們先來看一下 Array 的原型鏈:

    三個節點分別是:

    Array.prototype --> 有 concat, fill, find 等成員。

    Object.prototype -->

    null   -> 結束。

    好了,那麼我們來實現一下自己的原型鏈。

     1 var People = function () {
     2 };
     3 People.prototype.ff = function () {
     4   console.log('People.prototype.f');
     5 };
     6 
     7 const Man = function () {
     8 }
     9 
    10 Man.prototype = Object.create(People.prototype); // -------------->關聯起來, 注意是從People.prototype創建的
    11 Man.prototype.constructor = Man; // 構造函數,上圖上已經明確constructor要指向自己的構造函數。但是我們是從People.prototype創建的,
                          // 而Object.create並不會創建constructor, 需要我們去賦值。
    12 const m = new Man(); 13 14 m.ff();

    第10行進行關聯,使用 Man 創建 m 實例,可以找到 ff 函數。

    如果沒有第10行進行關聯,則會找不到 ff 函數。

    需要注意的是,我們使用 Object.create 進行創建,這個稍候再討論。

    雖然我們實現了原型鏈,但是成員變量property我們並沒有作處理,比如上面的代碼,如果在People中添加一個成員,在Man中是找不到的。

    如下代碼:

     1 var People = function () {
     2     this.p1 = 2;
     3 };
     4 People.prototype.ff = function () {
     5     console.log('People.prototype.f');
     6 };
     7 
     8 const Man = function () {
     9     this.m1 = 2;
    10 }
    11 
    12 Man.prototype = Object.create(People.prototype);
    13 Man.prototype.constructor = Man;
    14 const m = new Man();
    15 
    16 m.ff();
    17 
    18 console.log(m);

    打印出來的結果:

    m 只包含自己的m1成員。

    這個時候,我們需要從People繼承它的property. 具體實現就是在Man的構造函數中,使用People.call(this)。代碼如下:

     1 var People = function () {
     2     this.p1 = 2;
     3 };
     4 People.prototype.ff = function () {
     5     console.log('People.prototype.f');
     6 };
     7 
     8 const Man = function () {
     9     People.call(this);
    10     this.m1 = 2;
    11 }
    12 
    13 Man.prototype = Object.create(People.prototype);
    14 Man.prototype.constructor = Man;
    15 const m = new Man();
    16 
    17 m.ff();
    18 
    19 console.log(m);

    打印出來的結果:

    我們發現p1、m1都包含了。

    這也說明了,成員函數的繼承,其實是包含的關係,它並不像原型鏈一樣各自含有各自的東東。

    People.call(this)這句代碼,已經明確說明執行People的構造函數,而People使用的this就變成Man的this了。

    講到這裡,那麼繼承的實現也就很清晰了:

    1、繼承基類的成員變量。

    2、將原型鏈連起來。

    補充說明:

    Object.create. Javascript | MDN 的解釋:

    Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 

    則相當於:

    1 function create(obj) {
    2     function F(){};
    3     F.__proto__ = obj; //以传入参数为原型构造对象
    4     return new F(); 
    5 }  

     注意我們創建的代碼:

    Man.prototype = Object.create(People.prototype);
    Man.prototype.constructor = Man;

    相當於 Man.prototype.__proto__ = People.prototype;  ---> 指向父節點。

     所以這條鏈路就連起來了。

    const m = new Man()

    這個相當於:

    1 var o = new Object();
    2 o.__proto__ = Man.prototype;
    3 Man.call(o);

    了解原理後,我們就了解爲什麼有些人寫:

    Man.prototype = new People(); 可以通過。

    依據篇首圖形,我們知道實例(new出來的對象)含有 __proto__成員變量,正好與 prototype 一致,只不過缺少了 constructor,這個是有隱患的。

    hasOwnProperty

    用於判斷成員變量的,是不是prototype中的函數。

    因為成員變量繼承了過來,已經變成自己的成員,所以hasOwnProperty是可以判斷基類的成員的。

    如果 !hasOwnProperty,就會延著prototype鏈路檢索,直到null.

    isPrototypeOf
    用於判斷實例對象是否在原型鏈上。
    如:
    People.prototype.isPrototypeOf(m)
    instanceof
    判斷實例對象是否爲某個構建函數創建的。如:
    console.log(m instanceof Man) // true
    console.log(m instanceof aaa) // false
  • 相关阅读:
    java实现RSA非对称加密
    lombok中的@Builder注解
    java实现大文件的分割与合并
    IDEA新建springboot选择DevTools
    bat命令自动配置java环境变量
    java实现发送邮件
    随记
    编译原理学习——FIRST和LASTVT
    国王的游戏
    JAVA类加载及NEW对象的过程
  • 原文地址:https://www.cnblogs.com/lin277541/p/10512356.html
Copyright © 2011-2022 走看看