欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

繼承與原型鏈

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

幾乎所有 JavaScript 中的對(duì)象都是位于原型鏈頂端的 Object 的實(shí)例。

繼承屬性

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

代碼實(shí)例

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 的自身屬性可以直接返回值
  • 為啥我們?cè)O(shè)置 fn.prototype.b=3,返回的還是 2 呢?,因?yàn)槲覀儾檎易陨碛羞@個(gè)屬性時(shí)就直接返回了,不會(huì)在往上面查找了。
  • c 不是 o 的自身屬性,所以會(huì)到 o.prototype 上去查找,發(fā)現(xiàn)有 c,直接返回值
  • d 不是 o 的自身屬性,所以會(huì)到 o.prototype 上去查找,發(fā)現(xiàn)沒有,再到 o.protype.prototype 上查找,發(fā)現(xiàn)為 null,停止搜索,返回 undefined

看下 o 構(gòu)造函數(shù)的打印

{
    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 里,任何函數(shù)都可以添加到對(duì)象上作為對(duì)象的屬性。函數(shù)的繼承與其他的屬性繼承沒有差別,包括上面的“屬性遮蔽”(這種情況相當(dāng)于其他語言的方法重寫)。

當(dāng)繼承的函數(shù)被調(diào)用時(shí),this 指向的是當(dāng)前繼承的對(duì)象,而不是繼承的函數(shù)所在的原型對(duì)象。

var o = {
  a: 2,
  m: function () {
    return this.a + 1;
  },
};

console.log(o.m()); // 3
// 當(dāng)調(diào)用 o.m 時(shí),'this' 指向了 o.

var p = Object.create(o);
// p是一個(gè)繼承自 o 的對(duì)象

p.a = 4; // 創(chuàng)建 p 的自身屬性 'a'
console.log(p.m()); // 5
// 調(diào)用 p.m 時(shí),'this' 指向了 p
// 又因?yàn)?p 繼承了 o 的 m 函數(shù)
// 所以,此時(shí)的 'this.a' 即 p.a,就是 p 的自身屬性 'a'

在 JavaScript 中使用原型

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

function doSomething() {}
console.log(doSomething.prototype);
// 和聲明函數(shù)的方式無關(guān),
// JavaScript 中的函數(shù)永遠(yuǎn)有一個(gè)默認(rèn)原型屬性。
var doSomething = function () {};
console.log(doSomething.prototype);

在控制臺(tái)顯示的 JavaScript 代碼塊中,我們可以看到 doSomething 函數(shù)的一個(gè)默認(rèn)屬性 prototype。而這段代碼運(yùn)行之后,控制臺(tái)應(yīng)該顯示類似如下的結(jié)果:

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

我們可以給 doSomething 函數(shù)的原型對(duì)象添加新屬性,如下:

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

可以看到運(yùn)行后的結(jié)果如下:

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

現(xiàn)在我們可以通過 new 操作符來創(chuàng)建基于這個(gè)原型對(duì)象的 doSomething 實(shí)例。

代碼:

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

運(yùn)行的結(jié)果類似于以下的語句。

{
    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);

結(jié)果如下:

// doSomeInstancing的自身屬性,直接返回值
doSomeInstancing.prop:      some value
// 不是doSomeInstancing的自身屬性,查看原型對(duì)象,發(fā)現(xiàn)有這個(gè)屬性直接返回值
doSomeInstancing.foo:       bar
// 不是函數(shù)自身的屬性,也不是原型對(duì)象上的屬性,一層層往上找,最后查找到prototype為null時(shí),表示沒有這個(gè)屬性,所以返回undefined
doSomething.prop:           undefined
doSomething.foo:            undefined
doSomething.prototype.prop: undefined
// 查找doSomething原型對(duì)象有foo屬性,所以直接返回值
doSomething.prototype.foo:  bar

性能

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

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

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 中唯一一個(gè)處理屬性并且不會(huì)遍歷原型鏈的方法。

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

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

附:原型鏈?zhǔn)菍?shí)現(xiàn)繼承的主要方法

先說一下繼承,許多OO語言都支持兩張繼承方式:接口繼承、實(shí)現(xiàn)繼承。

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

? ? |- 實(shí)現(xiàn)繼承:繼承實(shí)際的方法

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

原型鏈基本思路:

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

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

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

總結(jié)

到此這篇關(guān)于Js繼承與原型鏈的文章就介紹到這了,更多相關(guān)Js繼承與原型鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • javascript 星級(jí)評(píng)分效果(手寫)

    javascript 星級(jí)評(píng)分效果(手寫)

    今天上午抽空隨手寫了個(gè)星級(jí)評(píng)分的效果,給大家分享下。由于水平有限,如有問題請(qǐng)指出;首先要準(zhǔn)備一張星星的圖片,灰色是默認(rèn)狀態(tài),黃色是選擇狀態(tài),需要的朋友可以參考下
    2012-12-12
  • js實(shí)現(xiàn)列表向上無限滾動(dòng)

    js實(shí)現(xiàn)列表向上無限滾動(dòng)

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)列表向上無限滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • 微信小程序Error:Fail?to?open?IDE問題的解決方法

    微信小程序Error:Fail?to?open?IDE問題的解決方法

    今天學(xué)習(xí)小程序時(shí)無法通過HBuilderX運(yùn)行微信小程序,查了相關(guān)資料后解決了,下面這篇文章主要給大家介紹了關(guān)于微信小程序Error:Fail?to?open?IDE問題的解決方法,需要的朋友可以參考下
    2023-04-04
  • 關(guān)于JS精度丟失產(chǎn)生的原因以及解決方案

    關(guān)于JS精度丟失產(chǎn)生的原因以及解決方案

    在處理一些極端情況下的復(fù)雜數(shù)值計(jì)算時(shí),我們可能會(huì)遇到這樣的情況,就是運(yùn)算結(jié)果丟失精度,下面這篇文章主要給大家介紹了關(guān)于JS精度丟失產(chǎn)生的原因以及解決方案的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • JavaScript字符串_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    JavaScript字符串_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    JavaScript中的字符串就是用''或""括起來的字符表示。下面通過本文給大家介紹JavaScript字符串的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2017-06-06
  • Bootstrap實(shí)現(xiàn)水平排列的表單

    Bootstrap實(shí)現(xiàn)水平排列的表單

    這篇文章主要為大家詳細(xì)介紹了Bootstrap實(shí)現(xiàn)水平排列的表單的相關(guān)代碼,代碼簡潔,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 微信小程序?qū)崿F(xiàn)短信驗(yàn)證碼倒計(jì)時(shí)

    微信小程序?qū)崿F(xiàn)短信驗(yàn)證碼倒計(jì)時(shí)

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)短信驗(yàn)證碼倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • JavaScript 實(shí)現(xiàn)同時(shí)選取多個(gè)時(shí)間段的方法

    JavaScript 實(shí)現(xiàn)同時(shí)選取多個(gè)時(shí)間段的方法

    這篇文章主要介紹了JavaScript 實(shí)現(xiàn)同時(shí)選取多個(gè)時(shí)間段的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • javascript基本算法匯總

    javascript基本算法匯總

    這篇文章主要為大家詳細(xì)介紹了javascript基本算法,包括輸出奇偶數(shù)控制算法、冒泡排序等,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 微信小程序 自定義復(fù)選框?qū)崿F(xiàn)代碼實(shí)例

    微信小程序 自定義復(fù)選框?qū)崿F(xiàn)代碼實(shí)例

    這篇文章主要介紹了微信小程序 自定義復(fù)選框?qū)崿F(xiàn)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09

最新評(píng)論