聊聊js最無聊的技術點-原型鏈

寫在前面

js 作爲一種動態語言,他的強大之處已經不用我來廢話了,那麼如果要學習js,你可以學習一些基礎入門的簡單的,也就是我們常用的一些操作數組啊、格式轉化啊等,這些爲什麼簡單呢?其實本質不是它多簡單,是它的實用性有多強,我們在寫項目的時候很多的時候用到的知識點我們認爲是很簡單的,原因是是因爲我們用了,所以覺得簡單,它的簡單與否和它本身的難度是沒有必然關係的,所以說這麼多的意思呢就是今天要說的原型鏈其實不是很難,只是我們覺得它比較難,原因很簡單,我們切實感受到他的存在的時候不多。那麼今天我們就簡單的會會這個js裏面最無聊的部分,原型鏈。

什麼是原型鏈

  • 實例對象和原型對象之間的關係就叫做原型鏈
    看到這句話心裏罵人的估計不少,其實說人話就是我們寫一個構造函數,然後構造函數實例化一個對象,他們之間的關係,也就是__proto__ 和prototype之間的關係,下面我們舉個例子:
/**
		 * Gzfun 進行驗證實例化對象是可以直接調構造函數原型屬性和方法的。  實例對象和原型之間的關係是通過實例化對象的__proto__(原型)進行聯繫的。 這麼關係就叫做原型鏈
		 * 原型鏈本身是一種關係,實例對象的原型(__proto__)和構造函數原型(prototype)之間的一種關係就是原型鏈(或者說實例對象和原型對象之間的一種關係就叫做原型鏈)    
		 * 實例對象和構造函數是沒有直接關係的,實例對象只是構造函數的創造出來的。
		 * @param {Object} param1
		 * @param {Object} param2
		 */
		function Gzfun(param1, param2) {
			this.param1 = param1;
			this.param2 = param2;
			this.sayhello = function() {
				console.info("hello")
			}
		}
		//給原型加上屬性和方法
		Gzfun.prototype.param3 = "value3";
		Gzfun.prototype.saybye = function() {
			console.info("bye-bye");
		}
		//實例化一個對象並且初始化
		var gzfun = new Gzfun("value1", "value2");
		//調原型鏈上面的方法
		gzfun.saybye();
		gzfun.sayhello();
		console.dir(gzfun);
		console.dir(Gzfun);
		//判斷構造函數原型的prototype 是和我們實例化對象上面的__proto__對象是相等的
		console.info(gzfun.__proto__ === Gzfun.prototype)

驗證原型鏈中的this指向問題

/**
		 * 驗證原型對象中方法的this就是實例對象
		 * @param {Object} val
		 */
		
		function Check_Proto(val) {
			this.val = val;
			console.info(this); //這個this其實就是下面的check_proto 和 ch
		}
		Check_Proto.prototype.sayhi = function() {
			console.info(this); 
			console.info("hi");
			return "123";
		} 
		var check_proto = new Check_Proto("value1");
		var ch = new Check_Proto();
		console.info(check_proto, ch.val, ch.sayhi());
		/**
		 * 結論1:原型對象中方法的this就是實例對象
		 * 結論2:構造函數中的this就是實例對象
		 */

運行結果

在這裏插入圖片描述

解釋一波:上面的可以看得出來我們首先在構造函數裏面打印了this,我們想知道的是他和我們實例化的對象有什麼關係,所以在最後的時候我們將實例化的對象直接打印出來,可以看的出來,其實原型對象中的this就是實例對象

驗證原型鏈的指向是不是可以改變

既然我們可以直接在構造函數上面添加一個新的屬性出來,那麼是不是我們將這個初始化的對象重定向一個新的構造函數以後他的指向就發生改變了呢?我們測試一下:

function Check_Proto1() {
			console.info("我是Check_Proto1");
		}
		Check_Proto1.prototype.saych1 = function() {
			console.info("您好,我是Check_Proto1")
		}

		function Check_Proto2() {

		}
		//給Check_Proto2原型加上一個函數
		Check_Proto2.prototype.sayche2 = function(){
			
		}
		//Check_Proto2 的原型指向來Check_Proto1的對象    
		Check_Proto2.prototype = new Check_Proto1();
		var ch2 = new Check_Proto2();
		ch2.saych1();

在這裏插入圖片描述

  • 我們可以看到,我首先是聲明瞭一個構造函數Check_Proto1,然後我們給Check_Proto1添加原型屬性,saych1函數,這個時候我們聲明第二個構造函數,我們同樣給第二個添加原型函數saych2,此時我們Check_Proto1的實例化的對象給到Check_Proto2的原型對象,這個時候我們實例化Check_Proto2,看一下能不能調的通Check_Proto1的原型函數,看結果就明白了,其實是可以的,說明Check_Proto2的原型對象的指向改變了。

結論

結論:當我們不寫Check_Proto2.prototype = new Check_Proto1(); 的時候也就是我們不將原型鏈上面的指向改變的時候我們ch2的對象是有構造函數的方法的,也就是sayche2
也就是我們可以直接調che2.sayche2()的函數,但是當我們的原型鏈的指向發生改變的時候,我們的ch2的sayche2的函數就不復存在來,說明來我們的原型鏈的指向是可以發生改變的。
結論:構造函數的原型對象(prototype) 如果發生改變,那麼實例化的對象的原型(proto)也會跟着發生改變 他們的關係是通過是通過__proto__進行聯繫的。

原型鏈實現繼承

寫過java的基本都是知道的,java的三大特性:封裝、繼承、多態,那麼我們的js其實也是有的,我們下面使用原型鏈的特性實現一個基本的繼承,這裏簡單的解釋一下什麼是繼承,我們都知道java是一門以類作爲記一個基礎的語言,所謂的類其實就是類別,我們在寫函數的時候很多的名字都是有意義的,比如說人就是一個大類,那麼人還包括什麼呢?女人、男人還可以分爲大人、小孩、等等類別,那麼不管是什麼人,都有的特性就是有思想,會喫,會喝等特性,但是小類裏面又可以分爲男人、女人他們的特性呢?女人可以生孩子,很偉大的一個特性,男人可以撐起來一個家、也很偉大,那麼這些就是一些比較特殊的特性,我們在寫函數的時候如果分爲了小類作爲函數的話,那麼我們希望的是女人不僅僅可以生孩子,還要可以喫,喝等人有的特性,這個時候我們不需要再聲明一個人的函數,我們只需要將人的大類被女人的小類繼承,那麼女人的這個類別就有了人類的特性,這個就是繼承的基本實現過程。至於說封裝和多態這裏就不說了,都是相互依賴的,沒有繼承也不會有多態了,沒有不停的封裝也不會有所謂的繼承了,這個喜歡java的慢慢研究,我這裏就不班門弄斧了。

源碼

function notebook(keyword,number){
			this.keyword = keyword;
			this.number = number;
		}
		notebook.prototype.wirte = function(){
			console.info("筆記本是可以打字的")
		}
		notebook.prototype.playvideo = function(){
			console.info("筆記本是可以放視頻的")
		}
		//mbp自帶的一些屬性
		function macpro(bar){
			this.bar = bar;
		}
		//將蘋果筆記本的原型指向notebook的實例對象,進行一個繼承的操作
		macpro.prototype = new notebook("鍵盤","數字鍵");
		macpro.prototype.havebar = function(){
			console.info("我是蘋果筆記本我有bar");
		}
		var macp = new macpro("這是蘋果的touchbar");
		console.info(macp.keyword);
		console.info(macp.number);
		macp.wirte();
		macp.playvideo();
		console.info(macp.bar);
		macp.havebar();

代碼很簡單,但是簡單的做一個解釋,因爲上面的解釋還是比較少的,我們首先給構造函數notebook兩個基本的參數屬性,然後我們原型對象上添加兩個方法,然後我們新建一個macpro的構造函數,這個函數也屬於筆記本的一類,那麼我他也應該具有的屬性就是可以打字,可以放視頻,同時有鍵盤等屬性,但是macpro有什麼特性呢?有touchbar,這是一般的筆記本沒有的,我們這個時候將macpro的原型指向notebook的構造函數也就是實例對象,我們就有了notebook的基本屬性,下面看一下打印的結果:

結果

鍵盤
原型鏈.html:121 數字鍵
原型鏈.html:105 筆記本是可以打字的
原型鏈.html:108 筆記本是可以放視頻的
原型鏈.html:124 這是蘋果的touchbar
原型鏈.html:117 我是蘋果筆記本我有bar

  • 由於在火車上,這裏沒辦法登錄截圖的軟件,就直接複製了,擔待一下!

總結

寫到這裏,關於原型鏈的基本的介紹就不寫了,我也覺得這個東西很無聊,所以也是耐着性子寫完的,不過這個東西確實是很有必要的一個東西,我們如果看過juqery和vue的源碼的話,會發現,裏面其實是大量的原型鏈進行實現的基本功能,所以說還是很有必要研究的一個東西,以後還會寫一些關於原型鏈的知識點,今天就先這樣了,拜拜!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章