久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      淺析JavaScript的繼承和原型鏈

      本篇文章給大家?guī)砹薺avascript中繼承和原型鏈的相關(guān)知識,其中包括構(gòu)造函數(shù)、原型以及class語法糖的相關(guān)問題,希望對大家有幫助。

      淺析JavaScript的繼承和原型鏈

      淺析JavaScript的繼承和原型鏈

      一、前言

      JavaScript的繼承和原型鏈?zhǔn)俏以趯W(xué)習(xí)前端過程中遇到的較為少有的難以理解的部分,這里便將我所有知道和了解到的東西記錄了下來,希望能夠給還在這里面苦苦掙扎的兄弟萌一點(diǎn)點(diǎn)小的幫助,也歡迎各位大佬批評指正。

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

      2.1 構(gòu)造函數(shù)的實(shí)例成員和靜態(tài)成員

      構(gòu)造函數(shù)由實(shí)例成員和靜態(tài)成員二者組成,其中實(shí)例成員是在函數(shù)內(nèi)部通過this關(guān)鍵字添加的成員;只能通過實(shí)例化對象以后通過實(shí)例化對象進(jìn)行訪問;而靜態(tài)成員是函數(shù)本身上添加的成員,只能通過構(gòu)造函數(shù)來訪問。

      //創(chuàng)造一個構(gòu)造函數(shù)let Father = function(name,age){     //實(shí)例成員     this.name = name;     this.age = age;     this.method = "我是一個實(shí)例成員";}     //靜態(tài)成員Father.like = "mother";     //檢驗(yàn)實(shí)例對象是否能夠被構(gòu)造函數(shù)直接訪問console.log(Father.method);     //undefinedconsole.log(Father.like);     //mother     //實(shí)例化一個對象let father = new Father("小王",27);     //檢驗(yàn)靜態(tài)對象是否能夠被實(shí)例化對象訪問console.log(father.name);     //小王console.log(father.age);     //27console.log(father.like);     //undefined

      2.2 實(shí)例化對象的過程

      通過new關(guān)鍵字可以通過構(gòu)造函數(shù)實(shí)現(xiàn)一個實(shí)例化對象,那么在具體實(shí)例化的過程中發(fā)生了什么呢?大致可以劃分為以下幾個步驟:

      (1) 創(chuàng)建一個空對象 son {}

      (2) 為 son 準(zhǔn)備原型鏈連接 son.__proto__ = Father.prototype

      (3) 重新綁定this,使構(gòu)造函數(shù)的this指向新對象 Father.call(this)

      (4) 為新對象屬性賦值 son.name

      (5) 返回this return this,此時的新對象就擁有了構(gòu)造函數(shù)的方法和屬性了

      一個小問題:所有實(shí)例化對象的方法都是共享的嗎?

      構(gòu)造函數(shù)的方法分為兩種,第一種為在函數(shù)內(nèi)部直接定義的方法,第二種為通過原型添加的方法;

      //函數(shù)內(nèi)部直接定義的方法let Father = function(){     this.read = function(){         console.log("我是內(nèi)部定義的read方法!");     }}//通過原型鏈添加的方法Father.prototype.look = function(){     console.log("我是通過原型鏈定義的look方法!");}     //實(shí)例化對象進(jìn)行檢驗(yàn)let father1 = new Father();let father2 = new Father();     father1.read();     //我是內(nèi)部定義的read方法!father2.read();     //我是內(nèi)部定義的read方法!console.log(father1.read === father2.read);     //falsefather1.look();     //我是通過原型鏈定義的look方法!father2.look();     //我是通過原型鏈定義的look方法!console.log(father1.look === father2.look);     /true

      可以發(fā)現(xiàn),函數(shù)內(nèi)部直接定義的方法在每實(shí)例化一個新的對象以后,都會給這個方法分配一個新的內(nèi)存空間,而通過原型添加的方法便會共享一個空間。

      一個小問題:所有實(shí)例化對象的屬性都是共享的嗎?

      不存在內(nèi)存空間的問題,判斷時看其值是否相同;

      let Father = function(name){     this.name = name;}let father1 = new Father("小王");     let father2 = new Father("小紅");     console.log(father1.name === father2.name);     //falselet father1 = new Father("小王");     let father2 = new Father("小王");     console.log(father1.name === father2.name);     //true

      因此我們可以總結(jié)一下定義構(gòu)造函數(shù)的基本規(guī)則,即公共屬性定義到構(gòu)造函數(shù)里面,公共方法我們放到原型對象身上。

      三、原型

      3.1 什么是原型

      Father.prototype 就是原型,它是一個對象,也可以稱為原型對象。

      3.2 原型的作用是什么

      原型的作用,就是共享方法。

      我們通過 Father.prototype.method 可以共享方法,不會反應(yīng)開辟空間存儲方法。

      3.3 原型中的this指向哪兒

      原型中this的指向是實(shí)例。

      四、原型鏈

      原型鏈本人感覺是一個對于初學(xué)者或者說是部分前端菜雞(例如本人)來說特別難以理解的東西,為了讓下面的部分更容易理解,這里強(qiáng)行先記住以下幾點(diǎn):

      1. __proto__是每個對象都有的屬性,prototype是每個函數(shù)特有的方法;
      2. 每個對象的__proto__屬性都會指向自身構(gòu)造函數(shù)的prototype;
      3. constructor屬性始終指向創(chuàng)建當(dāng)前對象的構(gòu)造函數(shù);
      4. Function.__proto__ === Function.prototype;
      5. Object.prototype.__proto__ === null 也就是原型鏈的終點(diǎn);

      4.1 什么是原型鏈

      原型與原型層層相鏈接的過程即為原型鏈。

      4.2 原型鏈的應(yīng)用

      對象可以使用構(gòu)造函數(shù)prototype原型對象的屬性和方法,就是因?yàn)閷ο笥?code>__proto__原型的存在每個對象都有__proto__原型的存在

      let Father = function(name){     this.name = name;}let father = new Father("老王");console.log(father.__proto__ === Father.prototype);     //true     //驗(yàn)證上述說法中的第二條

      4.3 原型鏈圖

      淺析JavaScript的繼承和原型鏈

      結(jié)合寫在最前面的幾點(diǎn),理解上圖應(yīng)該問題不大了,圖中圈起來的部分就是駭人聽聞的原型鏈。

      4.4 原型鏈的查找方式

      function Star(name) { 	this.name = name; 	//(1)首先看obj對象身上是否有dance方法,如果有,則執(zhí)行對象身上的方法 	this.dance = function () { 		console.log(this.name + '1'); 	}}//(2)如果沒有dance方法,就去構(gòu)造函數(shù)原型對象prototype身上去查找dance這個方法。Star.prototype.dance = function () { 	console.log(this.name + '2');}; 	//(3)如果再沒有dance方法,就去Object原型對象prototype身上去查找dance這個方法。Object.prototype.dance = function () { 	console.log(this.name + '3');}; 	//(4)如果再沒有,則會報錯。let obj = new Star('小紅');obj.dance();

      (1)首先看obj對象身上是否有dance方法,如果有,則執(zhí)行對象身上的方法。

      (2)如果沒有dance方法,就去構(gòu)造函數(shù)原型對象prototype身上去查找dance這個方法。

      (3)如果再沒有dance方法,就去Object原型對象prototype身上去查找dance這個方法。

      (4)如果再沒有,則會報錯。

      一個小問題:在原型上添加方法需要注意的地方

      有兩種添加方法,第一種為上面的寫法,直接通過 構(gòu)造函數(shù).prototype.方法名 進(jìn)行添加;第二種為重定義構(gòu)造函數(shù)的prototype,但是此種情況會丟失掉原有的constructor構(gòu)造器,所以一定要再連接回去,例子如下:

      function Star(name) { 	this.name = name;}Star.prototype = {     dance:function(){     	console.log("重定義prototype"); 	}}Star.prototype.constructor = Star;

      另外,類似于Array、String這些內(nèi)置的類是不能這么處理的。

      五、繼承

      這里就長話短說,首先我們要明確繼承需要繼承哪些東西,在前文中我們提到了定義構(gòu)造函數(shù)的基本規(guī)則,即**公共屬性定義到構(gòu)造函數(shù)里面,公共方法我們放到原型對象身上。**我們所需要繼承的東西也不外乎就這二者,公共屬性的繼承可以通過call()或者apply()進(jìn)行this的指向定義,而公共方法可以通過原型對象的賦值進(jìn)行處理,因此我們很容易想到如下的方法:

      //定義一個父類function Father(name) { 	this.name = name;}Father.prototype.dance = function () { 	console.log('I am dancing');};//定義一個子類function Son(name, age) { 	Father.call(this, name); 	this.age = age;}//通過賦值的方法連接Son.prototype = Father.prototype;//為子類添加方法Son.prototype.sing = function () { 	console.log('I am singing');}; 	let son = new Son('小紅', 100); 	//此時父類也被影響了console.log(Father.prototype)  	//{dance: ?, sing: ?, constructor: ?}

      很顯然,當(dāng)我們只想修改子類里面的方法時,顯然上述方法不太合適;因此 我們可以嘗試new一個新的父類出來,代碼如下:

      function Father(name) { 	this.name = name;}Father.prototype.dance = function () { 	console.log('I am dancing');};function Son(name, age) { 	Father.call(this, name); 	this.age = age;}Son.prototype = new Father();Son.prototype.sing = function () { 	console.log('I am singing');};let son = new Son('小紅', 100);console.log(Father.prototype)  	//{dance: ?, constructor: ?}

      六、class語法糖

      對于以前了解過面向?qū)ο缶幊痰某绦騿T來講,上述關(guān)于繼承的寫法屬實(shí)讓人有些難以接受,因此在es6里面新增了一個語法糖來更方便更便捷地書寫繼承,這里就直接上代碼了;

      class Father { 	constructor(name) { 		this.name = name; 	} 	dance() { 		console.log("我是" + this.name + ",我今年" + this.age + "歲," + "我在跳舞"); 	}}class Son extends Father { 	constructor(name, age) { 		super(name); 		this.age = age; 	} 	sing() { 		console.log("我是" + this.name + ",我今年" + this.age + "歲," + "我在唱歌"); 	}}let obj = new Son('小紅', 19); 	obj.sing();obj.dance();

      分析一下上面代碼,首先一個類(構(gòu)造函數(shù))里面依舊為兩部分,即公共屬性和公共方法,constructor() 里面存放了該構(gòu)造函數(shù)的公共屬性,后面接著的便是公共方法,extends 關(guān)鍵字表示繼承的是哪個類,super() 便是將里面父類里面相應(yīng)的公共屬性拿出來,這樣看下來便可以將代碼規(guī)整許多。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號