最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一篇文章讓你看懂Js繼承與原型鏈

 更新時間:2021年12月10日 10:40:40   作者:前端工程師天明  
原型鏈是一種關系,實例對象和原型對象之間的關系,關系是通過原型(__proto__)來聯(lián)系的,下面這篇文章主要給大家介紹了關于Js繼承與原型鏈的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

繼承與原型鏈

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

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

繼承屬性

JavaScript 對象是動態(tài)的屬性“包”(指其自己的屬性)。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 上去查找,發(fā)現有 c,直接返回值
  • d 不是 o 的自身屬性,所以會到 o.prototype 上去查找,發(fā)現沒有,再到 o.protype.prototype 上查找,發(fā)現為 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; // 創(chuàng)建 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 操作符來創(chuàng)建基于這個原型對象的 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的自身屬性,查看原型對象,發(fā)現有這個屬性直接返回值
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繼承與原型鏈內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • js實現帶翻轉動畫圖片時鐘

    js實現帶翻轉動畫圖片時鐘

    這篇文章主要為大家詳細介紹了js實現帶翻轉動畫的圖片時鐘,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • JS前端認證授權技巧歸納總結

    JS前端認證授權技巧歸納總結

    這篇文章主要為大家介紹了JS前端認證授權技巧歸納總結,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • JavaScript常用工具函數大全

    JavaScript常用工具函數大全

    這篇文章主要介紹了JavaScript常用工具函數,匯總整理了各種JavaScript常用工具函數,包括獲取、判斷、轉換、設置等相關功能函數的定義與使用方法,需要的朋友可以參考下
    2020-05-05
  • 讓JavaScript和其它資源并發(fā)下載的方法

    讓JavaScript和其它資源并發(fā)下載的方法

    這篇文章主要介紹了讓JavaScript和其它資源并發(fā)下載的方法,JavaScript并發(fā)下載主要目的在于解決JS加載會阻礙頁面呈現的問題,需要的朋友可以參考下
    2014-10-10
  • 詳解JavaScript中return的用法

    詳解JavaScript中return的用法

    這篇文章主要介紹了JavaScript中return的用法,包括return定義,寫法等方面的知識,需要的朋友可以參考下
    2017-05-05
  • 微信小程序支付及退款流程詳解

    微信小程序支付及退款流程詳解

    近期在做微信小程序時,涉及到了小程序的支付和退款流程,所以也大概的將這方面的東西看了一個遍,就在這篇文章里總結一下
    2017-11-11
  • JavaScript獲取對象key的幾種方法和區(qū)別

    JavaScript獲取對象key的幾種方法和區(qū)別

    這篇文章主要介紹了JavaScript獲取對象key的幾種方法和區(qū)別,下面文章更多的相關資料需要的小伙伴可以參考一下,希望對你有所幫助
    2022-03-03
  • ionic中列表項增加和刪除的實現方法

    ionic中列表項增加和刪除的實現方法

    在項目中遇到表單似的頁面,需要進行增加一行和減少一行的操作,基于ionic怎么實現呢?下面小編給大家分享ionic中列表項增加和刪除的實現方法,一起看看吧
    2017-01-01
  • js提示框替代系統(tǒng)alert,自動關閉alert對話框的實現方法

    js提示框替代系統(tǒng)alert,自動關閉alert對話框的實現方法

    下面小編就為大家?guī)硪黄猨s提示框替代系統(tǒng)alert,自動關閉alert對話框的實現方法。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • js給selected添加options的方法

    js給selected添加options的方法

    這篇文章主要介紹了js給selected添加options的方法,涉及javascript動態(tài)添加頁面下拉列表selected的技巧,需要的朋友可以參考下
    2015-05-05

最新評論

扬中市| 汨罗市| 宜阳县| 红原县| 桂林市| 新沂市| 麟游县| 临安市| 汝城县| 资阳市| 曲麻莱县| 改则县| 信宜市| 横山县| 清新县| 道孚县| 南城县| 浦江县| 临桂县| 泸西县| 子长县| 门源| 元江| 沐川县| 孝感市| 乌拉特前旗| 海兴县| 诏安县| 阿荣旗| 中宁县| 三都| 潞城市| 辉县市| 桃源县| 东宁县| 余庆县| 武穴市| 延庆县| 阿城市| 静乐县| 集安市|