成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

溫故js系列(15)-原型&原型鏈&原型繼承

Ethan815 / 3184人閱讀

摘要:給添加屬性給的原型對象添加屬性原型鏈在中,每個對象都有一個屬性,其保存著的地址就構(gòu)成了對象的原型鏈。實(shí)例變量實(shí)例函數(shù)原型鏈繼承有了原型鏈,就可以借助原型鏈實(shí)現(xiàn)繼承。是中唯一一個處理屬性但是不查找原型鏈的函數(shù)。

前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總

歡迎提issues斧正:原型&原型鏈&原型繼承

JavaScript-原型&原型鏈&原型繼承

JavaScript的原型是一個重要的知識點(diǎn),很多擴(kuò)展應(yīng)用都是從原型出發(fā)的。要說原型,我們先簡單說一下函數(shù)創(chuàng)建過程。上一篇文章用閉包實(shí)現(xiàn)類和繼承中用的是原型繼承,今天就講一講原型繼承。更多繼承在后面的文章中更新。

函數(shù)創(chuàng)建過程
function Xzavier() {};

1.創(chuàng)建一個對象(有constructor屬性及[[Prototype]]屬性),其中[[Prototype]]屬性不可訪問、不可枚舉。
2.創(chuàng)建一個函數(shù)(有name、prototype屬性),再通過prototype屬性 引用第1步創(chuàng)建的對象。
3.創(chuàng)建變量Xzavier,同時(shí)把函數(shù)的引用賦值給變量Xzavier。

構(gòu)造函數(shù)

構(gòu)造函數(shù)是用來新建同時(shí)初始化一個新對象的函數(shù),所以,任何一個函數(shù)都可以是構(gòu)造函數(shù)。只是我們在寫代碼的時(shí)候一般首字母大寫以便區(qū)分使用。

原型

每個函數(shù)在創(chuàng)建的時(shí)候js都自動添加了prototype屬性,這就是函數(shù)的原型,原型就是函數(shù)的一個屬性,類似一個指針。原型在函數(shù)的創(chuàng)建過程中由js編譯器自動添加。

function Xzavier() {
    this.name = "xzavier";
    this.sex = "boy";
    this.job = "jser";
}
//給A添加屬性
Xzavier.age = 23;
//給A的原型對象添加屬性
Xzavier.prototype.sports = function() {console.log("basketball")}
Xzavier.prototype = {
    hobbit1: function() {console.log("basketball");},
    hobbit2: function() {console.log("running");}
}; 
原型鏈

在JavaScript中,每個對象都有一個[[Prototype]]屬性,其保存著的地址就構(gòu)成了對象的原型鏈。
[[Prototype]]屬性是js編譯器在對象被創(chuàng)建時(shí)自動添加的,其取值由new運(yùn)算符的右側(cè)參數(shù)決定。字面量的方式可轉(zhuǎn)化為new Obejct();

var x = new Xzavier();
vae o = {};  //var o = new Obejct();

通過對象的[[Prototype]]保存對另一個對象的引用,通過這個引用往上進(jìn)行屬性的查找,這就是原型鏈查找機(jī)制。

對象在查找某個屬性的時(shí)候,會首先遍歷自身的屬性,如果沒有則會繼續(xù)查找[[Prototype]]引用的對象,如果再沒有則繼續(xù)查找[[Prototype]].[[Prototype]]引用的對象,依次類推,直到[[Prototype]].….[[Prototype]]undefined

var str = new String("xzavier");
str

Object.prototype[[Prototype]]就是undefined

function Xzavier() {
    this.name = "xzavier";
}
var x = new Xzavier();
x.age = 23;

console.log(x.job);  // 獲取x的job屬性 undefined

1、遍歷x對象本身,結(jié)果x對象本身沒有job屬性
2、找到x的[[Prototype]],也就是其對應(yīng)的對象Xzavier.prototype,同時(shí)進(jìn)行遍歷。 Xzavier.prototype也沒有job屬性
3、找到Xzavier.prototype對象的[[Prototype]],指向其對應(yīng)的對象Object.prototype。Object.prototype也沒有job屬性
4、尋找Object.prototype的[[Prototype]]屬性,返回undefined。

函數(shù)的變量和內(nèi)部函數(shù)

說了函數(shù)的原型鏈,這里需要說一下的變量和內(nèi)部函數(shù)。

私有變量和內(nèi)部函數(shù)

私有成員,即定義函數(shù)內(nèi)部的變量或函數(shù),外部無法訪問。

function Xzavier(){
    var name = "xzavier"; //私有變量
    var sports = function() {console.log("basketball")}; //私有函數(shù) 
}
var x = new Xzavier();
x.name;  //undefined

如果要訪問,需要對外提供接口。

function Xzavier(){
    var name = "xzavier"; //私有變量
    var sports = function() {console.log("basketball")}; //私有函數(shù)
    return{
        name: name,
        sports: sports
    }
}
var x = new Xzavier();
x.name;  //"xzavier"
靜態(tài)變量和內(nèi)部函數(shù)

用點(diǎn)操作符定義的靜態(tài)變量和內(nèi)部函數(shù)就是實(shí)例不能訪問到的變量和內(nèi)部函數(shù)。只能通過自身去訪問。

function Xzavier(){
    Xzavier.name = "xzavier"; //靜態(tài)變量
    Xzavier.sports = function() {console.log("basketball")}; //靜態(tài)函數(shù) 
}
Xzavier.name; //"xzavier"
var x = new Xzavier();
x.name;  //undefined
實(shí)例變量和內(nèi)部函數(shù)

通過this定義給實(shí)例使用的屬性和方法。

function Xzavier(){
    this.name = "xzavier"; //實(shí)例變量
    this.sports = function() {console.log("basketball");}; //實(shí)例函數(shù) 
}
Xzavier.name; //undefined
var x = new Xzavier();
x.name;  //"xzavier"
原型鏈繼承

有了原型鏈,就可以借助原型鏈實(shí)現(xiàn)繼承。

function Xzavier() {
    this.name = "xzavier";
    this.sex = "boy";
    this.job = "jser";
}

function X() {};

X的原型X.prototype原型本身就是一個Object對象。F12打開控制臺輸入函數(shù),再打印X.prototype:

Object {
    constructor: X()
    __proto__: Object
}

prototype本身是一個Object對象的實(shí)例,所以其原型鏈指向的是Object的原型。

X.prototype = Xzavier.prototype
X.prototype = Xzavier.prototype;

這樣相當(dāng)于把X的prototype指向了Xzavier的prototype;
這樣只是繼承了Xzavier的prototype方法,Xzavier中的自定義方法則不繼承。

X.prototype.love = "dog";

這樣也會改變Xzavier的prototype,所以這樣基礎(chǔ)就不好。

X.prototype = new Xzavier()
X.prototype = new Xzavier();

這樣產(chǎn)生一個Xzavier的實(shí)例,同時(shí)賦值給X的原型,也即X.prototype相當(dāng)于對象:

{
    name: "xzavier", 
    sex: "boy", 
    job: "jser",
    [[Prototype]] : Xzavier.prototype
}

這樣就把Xzavier的原型通過X.prototype.[[Prototype]]這個對象屬性保存起來,構(gòu)成了原型的鏈接。
不過,這樣X產(chǎn)生的對象的構(gòu)造函數(shù)發(fā)生了改變,因?yàn)樵赬中沒有constructor屬性,只能從原型鏈找到Xzavier.prototype,讀出constructor:Xzavier。

var x = new X;
console.log(x.constructor);

輸出:
Xzavier() {
    this.name = "xzavier";
    this.sex = "boy";
    this.job = "jser";
}

手動改正:

X.prototype.constructor = X;

這是X的原型就多了個屬性constructor,指向X。這樣就OK。

function Xzavier() {
    this.name = "xzavier";
    this.sex = "boy";
    this.job = "jser";
}

function X(){}
X.prototype = new Xzavier();
var x = new X()
x.name  // "xzavier"
[[Prototype]],__proto__,prototype

關(guān)于我們經(jīng)常遇到的[[Prototype]],__proto__,prototype

我們在控制臺打印 var str = new String("xzavier"),展開查看屬性時(shí),只會看到__proto__,所以起作用的是__proto__,__proto__是對象的內(nèi)置屬性,是每個對象都有的屬性,但是這個屬性使用不標(biāo)準(zhǔn),所以不建議直接使用。但是,我們的原型鏈就是基于 __proto__的。通過構(gòu)造函數(shù)得到的實(shí)例的 __proto__ 屬性,指向其對應(yīng)的原型對象 String.prototype,這正如文中我們打印 var str = new String("xzavier") 中看到的一樣。

[[Prototype]]是一個隱藏屬性,指向的是這個對象的原型。幾乎每個對象有一個[[prototype]]屬性。

prototype是每個函數(shù)對象都具有的屬性,指向原型對象,如果原型對象被添加屬性和方法,那么由應(yīng)的構(gòu)造函數(shù)創(chuàng)建的實(shí)例會繼承prototype上的屬性和方法,這也是我們在代碼中經(jīng)常遇到的。構(gòu)造函數(shù)產(chǎn)生實(shí)例時(shí),實(shí)例通過其對應(yīng)原型對象的 constructor 訪問對應(yīng)的構(gòu)造函數(shù)對象。所以,我們繼承出來的實(shí)例往往沒有constructor,只是通過原型鏈查找,會讓我們產(chǎn)生錯覺,可參見本系列原型鏈文章。

hasOwnProperty

hasOwnProperty是Object.prototype的一個方法,判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性。
hasOwnProperty 是JavaScript中唯一一個處理屬性但是不查找原型鏈的函數(shù)。

function Xzavier() {
    this.name = "xzavier";
    this.sex = "boy";
    this.job = "jser";
}
//給A的原型對象添加屬性
Xzavier.prototype.sports = function() {console.log("basketball");};

var x = new Xzavier();
x.name; // "xzavier"
"sex" in x; // true

x.hasOwnProperty("job"); // true
x.hasOwnProperty("sports"); // false

當(dāng)檢查對象上某個屬性是否存在時(shí),hasOwnProperty 是非常推薦的方法。

繼承在js中使用頻繁。ES6也設(shè)計(jì)了專門的CLASS語法糖供開發(fā)者使用。
更多繼承方法在新的文章中更新...

難得周末,應(yīng)該運(yùn)動O(∩_∩)O~ 打打籃球,運(yùn)動運(yùn)動,有代碼,有籃球,有生活。。。
長時(shí)間不動肩膀(其實(shí)身體各地方都是),還真疼啊。希望程序猿們都健健康康的?。?!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/90946.html

相關(guān)文章

  • 溫故js系列(14)-閉包&垃圾回收&內(nèi)存泄露&閉包應(yīng)用&作用域&

    摘要:該對象包含了函數(shù)的所有局部變量命名參數(shù)參數(shù)集合以及,然后此對象會被推入作用域鏈的前端。如果整個作用域鏈上都無法找到,則返回。此時(shí)的作用域鏈包含了兩個對象的活動對象和對象。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:閉包 JavaScript-閉包 閉包(closure)是一個讓人又愛又恨的somet...

    Amio 評論0 收藏0
  • 溫故js系列(18)-對象&對象使用

    摘要:對象創(chuàng)建字面量方式構(gòu)造函數(shù)方式也可以這樣不過這樣的話,為何不選擇字面量方式字面量方式和方式的寫法是等價(jià)的,返回的結(jié)果是同種類的對象。構(gòu)造函數(shù)產(chǎn)生實(shí)例時(shí),實(shí)例通過其對應(yīng)原型對象的訪問對應(yīng)的構(gòu)造函數(shù)對象。 前端學(xué)習(xí):教程&模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試資源匯總 歡迎提issues斧正:對象&對象使用 Object對象 在 JavaScript 中,對...

    keke 評論0 收藏0
  • 匯總有關(guān)JS對象的創(chuàng)建與繼承

      之前也有和大家講過有關(guān)JS的對象創(chuàng)建和對象繼承,本篇文章主要為大家做個匯總和梳理?! S中其實(shí)就是原型鏈繼承和構(gòu)造函數(shù)繼承的毛病,還有就是工廠、構(gòu)造、原型設(shè)計(jì)模式與JS繼承。 JS高級程序設(shè)計(jì)4:class繼承的重點(diǎn),不只是簡簡單單的語法而已?! ο髣?chuàng)建  不難發(fā)現(xiàn),每一篇都離不開工廠、構(gòu)造、原型這3種設(shè)計(jì)模式中的至少其一!  那JS為什么非要用到這種3種設(shè)計(jì)模式了呢??  我們先從對...

    3403771864 評論0 收藏0
  • 溫故js系列(16)-數(shù)組&數(shù)組方法使用詳解

    摘要:創(chuàng)建數(shù)組數(shù)組字面量數(shù)組構(gòu)造函數(shù)參數(shù)為數(shù)組建議使用數(shù)組字面量方式,性能好,代碼少,簡潔,畢竟代碼少。數(shù)組判斷方法用來判斷某個值是否為。的這是最簡潔最直接的遍歷數(shù)組元素的語法。把數(shù)組轉(zhuǎn)換為本地?cái)?shù)組,并返回結(jié)果。 前端學(xué)習(xí):前端教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:數(shù)組&數(shù)組方法使用詳解 Array對象 之前一...

    morgan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<