91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何分析Js繼承與原型鏈

發布時間:2021-12-10 13:04:34 來源:億速云 閱讀:108 作者:柒染 欄目:開發技術

今天就跟大家聊聊有關如何分析Js繼承與原型鏈,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

    繼承與原型鏈

    當談到繼承時,JavaScript 只有一種結構:對象。每個實例對象(object)都有一個私有屬性(稱之為 proto )指向它的構造函數的原型對象(prototype)。該原型對象也有一個自己的原型對象(proto),層層向上直到一個對象的原型對象為 null。根據定義,null 沒有原型,并作為這個原型鏈中的最后一個環節。

    幾乎所有 JavaScript 中的對象都是位于原型鏈頂端的 Object 的實例。

    繼承屬性

    JavaScript 對象是動態的屬性“包”(指其自己的屬性)。JavaScript 對象有一個指向一個原型對象的鏈。當試圖訪問一個對象的屬性時,它不僅僅在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依次層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。

    代碼實例

    function fn() {
      this.a = 1;
      this.b = 2;
    }
    
    const o = new fn();
    
    fn.prototype.b = 3;
    fn.prototype.c = 4;
    console.log(o.a);
    console.log(o.b);
    console.log(o.c);
    console.log(o.d);
    // 1
    // 2
    // 4
    // undefined
    • a 和 b 是 o 的自身屬性可以直接返回值

    • 為啥我們設置 fn.prototype.b=3,返回的還是 2 呢?,因為我們查找自身有這個屬性時就直接返回了,不會在往上面查找了。

    • c 不是 o 的自身屬性,所以會到 o.prototype 上去查找,發現有 c,直接返回值

    • d 不是 o 的自身屬性,所以會到 o.prototype 上去查找,發現沒有,再到 o.protype.prototype 上查找,發現為 null,停止搜索,返回 undefined

    看下 o 構造函數的打印

    {
        a: 1
        b: 2
        __proto__:
            b: 3
            c: 4
            constructor: ? fn()
            __proto__:
                constructor: ? Object()
                hasOwnProperty: ? hasOwnProperty()
                isPrototypeOf: ? isPrototypeOf()
                propertyIsEnumerable: ? propertyIsEnumerable()
                toLocaleString: ? toLocaleString()
                toString: ? toString()
                valueOf: ? valueOf()
                __defineGetter__: ? __defineGetter__()
                __defineSetter__: ? __defineSetter__()
                __lookupGetter__: ? __lookupGetter__()
                __lookupSetter__: ? __lookupSetter__()
                get __proto__: ? __proto__()
                set __proto__: ? __proto__()
    }

    繼承方法

    JavaScript 并沒有其他基于類的語言所定義的“方法”。在 JavaScript 里,任何函數都可以添加到對象上作為對象的屬性。函數的繼承與其他的屬性繼承沒有差別,包括上面的“屬性遮蔽”(這種情況相當于其他語言的方法重寫)。

    當繼承的函數被調用時,this 指向的是當前繼承的對象,而不是繼承的函數所在的原型對象。

    var o = {
      a: 2,
      m: function () {
        return this.a + 1;
      },
    };
    
    console.log(o.m()); // 3
    // 當調用 o.m 時,'this' 指向了 o.
    
    var p = Object.create(o);
    // p是一個繼承自 o 的對象
    
    p.a = 4; // 創建 p 的自身屬性 'a'
    console.log(p.m()); // 5
    // 調用 p.m 時,'this' 指向了 p
    // 又因為 p 繼承了 o 的 m 函數
    // 所以,此時的 'this.a' 即 p.a,就是 p 的自身屬性 'a'

    在 JavaScript 中使用原型

    在 JavaScript 中,函數(function)是允許擁有屬性的。所有的函數會有一個特別的屬性 —— prototype 。默認情況下是 Object 的原型對象

    function doSomething() {}
    console.log(doSomething.prototype);
    // 和聲明函數的方式無關,
    // JavaScript 中的函數永遠有一個默認原型屬性。
    var doSomething = function () {};
    console.log(doSomething.prototype);

    在控制臺顯示的 JavaScript 代碼塊中,我們可以看到 doSomething 函數的一個默認屬性 prototype。而這段代碼運行之后,控制臺應該顯示類似如下的結果:

    {
        constructor: ? doSomething(),
        __proto__: {
            constructor: ? Object(),
            hasOwnProperty: ? hasOwnProperty(),
            isPrototypeOf: ? isPrototypeOf(),
            propertyIsEnumerable: ? propertyIsEnumerable(),
            toLocaleString: ? toLocaleString(),
            toString: ? toString(),
            valueOf: ? valueOf()
        }
    }

    我們可以給 doSomething 函數的原型對象添加新屬性,如下:

    function doSomething() {}
    doSomething.prototype.foo = "bar";
    console.log(doSomething.prototype);

    可以看到運行后的結果如下:

    {
        foo: "bar",
        constructor: ? doSomething(),
        __proto__: {
            constructor: ? Object(),
            hasOwnProperty: ? hasOwnProperty(),
            isPrototypeOf: ? isPrototypeOf(),
            propertyIsEnumerable: ? propertyIsEnumerable(),
            toLocaleString: ? toLocaleString(),
            toString: ? toString(),
            valueOf: ? valueOf()
        }
    }

    現在我們可以通過 new 操作符來創建基于這個原型對象的 doSomething 實例。

    代碼:

    function doSomething() {}
    doSomething.prototype.foo = "bar"; // add a property onto the prototype
    var doSomeInstancing = new doSomething();
    doSomeInstancing.prop = "some value"; // add a property onto the object
    console.log(doSomeInstancing);

    運行的結果類似于以下的語句。

    {
        prop: "some value",
        __proto__: {
            foo: "bar",
            constructor: ? doSomething(),
            __proto__: {
                constructor: ? Object(),
                hasOwnProperty: ? hasOwnProperty(),
                isPrototypeOf: ? isPrototypeOf(),
                propertyIsEnumerable: ? propertyIsEnumerable(),
                toLocaleString: ? toLocaleString(),
                toString: ? toString(),
                valueOf: ? valueOf()
            }
        }
    }

    我們可以看到 prop 是 doSomeInstancing 的自身屬性,doSomeInstancing 中的proto就是 doSomething.prototype

    我們打印下里面的屬性

    console.log("doSomeInstancing.prop:      " + doSomeInstancing.prop);
    console.log("doSomeInstancing.foo:       " + doSomeInstancing.foo);
    console.log("doSomething.prop:           " + doSomething.prop);
    console.log("doSomething.foo:            " + doSomething.foo);
    console.log("doSomething.prototype.prop: " + doSomething.prototype.prop);
    console.log("doSomething.prototype.foo:  " + doSomething.prototype.foo);

    結果如下:

    // doSomeInstancing的自身屬性,直接返回值
    doSomeInstancing.prop:      some value
    // 不是doSomeInstancing的自身屬性,查看原型對象,發現有這個屬性直接返回值
    doSomeInstancing.foo:       bar
    // 不是函數自身的屬性,也不是原型對象上的屬性,一層層往上找,最后查找到prototype為null時,表示沒有這個屬性,所以返回undefined
    doSomething.prop:           undefined
    doSomething.foo:            undefined
    doSomething.prototype.prop: undefined
    // 查找doSomething原型對象有foo屬性,所以直接返回值
    doSomething.prototype.foo:  bar

    性能

    在原型鏈上查找屬性比較耗時,對性能有副作用,這在性能要求苛刻的情況下很重要。另外,試圖訪問不存在的屬性時會遍歷整個原型鏈。

    遍歷對象的屬性時,原型鏈上的每個可枚舉屬性都會被枚舉出來。要檢查對象是否具有自己定義的屬性,而不是其原型鏈上的某個屬性,則必須使用所有對象從 Object.prototype 繼承的 hasOwnProperty 方法。下面給出一個具體的例子來說明它:

    console.log(doSomeInstancing.hasOwnProperty("prop"));
    // true
    
    console.log(doSomeInstancing.hasOwnProperty("bar"));
    // false
    
    console.log(doSomeInstancing.hasOwnProperty("foo"));
    // false
    
    console.log(doSomeInstancing.__proto__.hasOwnProperty("foo"));
    // true

    hasOwnProperty  是 JavaScript 中唯一一個處理屬性并且不會遍歷原型鏈的方法。

    另一種這樣的方法:Object.keys()

    注意:檢查屬性是否為 undefined 是不能夠檢查其是否存在的。該屬性可能已存在,但其值恰好被設置成了 undefined。

    附:原型鏈是實現繼承的主要方法

    先說一下繼承,許多OO語言都支持兩張繼承方式:接口繼承、實現繼承。

        |- 接口繼承:只繼承方法簽名

        |- 實現繼承:繼承實際的方法

    由于函數沒有簽名,在ECMAScript中無法實現接口繼承,只支持實現繼承,而實現繼承主要是依靠原型鏈來實現。

    原型鏈基本思路:

    利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。

    每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數想指針(constructor),而實例對象都包含一個指向原型對象的內部指針(__proto__)。如果讓原型對象等于另一個類型的實例,此時的原型對象將包含一個指向另一個原型的指針(__proto__),另一個原型也包含著一個指向另一個構造函數的指針(constructor)。假如另一個原型又是另一個類型的實例……這就構成了實例與原型的鏈條。

    原型鏈基本思路(圖解):

    如何分析Js繼承與原型鏈

    看完上述內容,你們對如何分析Js繼承與原型鏈有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    莱州市| 吴桥县| 灯塔市| 凤冈县| 岢岚县| 尚志市| 柞水县| 邓州市| 西青区| 阳朔县| 陵川县| 新津县| 和顺县| 光山县| 乌鲁木齐市| 五河县| 防城港市| 三江| 肥东县| 乐山市| 共和县| 阿巴嘎旗| 湖口县| 海南省| 丰顺县| 嘉峪关市| 丹凤县| 灌阳县| 成武县| 木兰县| 双鸭山市| 文安县| 志丹县| 象州县| 龙岩市| 五大连池市| 尼勒克县| 荣昌县| 湖北省| 屏边| 宁乡县|