淺談javascript中的繼承

函數預編譯的過程

函數預編譯發生在函數執行之前
只有函數表達式纔可以執行,函數聲明並不可以執行。
預編譯時函數會生成自己的執行上下文。每個執行上下文都是獨一無二的,在函數執行完成時,銷燬執行上下文。
預編譯的過程可以分爲以下4個步驟:

  1. 形成了自己的執行上下文,變量提升,這時執行上下文裏存儲所有作用域中的變量。
  2. 若有形參,找出所有形式參數,存到形成的執行上下文裏中。若形參與變量名重複,則形參覆蓋變量。
  3. 給形參賦值;
  4. 函數提升,若函數內部還聲明瞭其它函數,則將函數存到執行上下文中;
Star.prototype = {};
   var Star = function() {};
   var star1 = new Star();

在javaScript 中我們通常並不會關心構造函數(Star)的原型指向誰(這裏Star的原型應指向Function.prototype)。
javascript 中並沒有真正的類,而我們所說的繼承可以理解成委託。

當new的時候發生了什麼

    var Star = function() {};
    var star1 = new Star();

new Star()時也會執行Star函數,所以會觸發預編譯過程。
Star函數在預編譯時,在自己的函數作用域裏聲明瞭一個變量this,此時this的值爲{}。
函數都具有返回值所以在構造函數內部會 return this

當在構造函數中訪問原型上的屬性a時,實際上是將a屬性複製了一份,當你在構造函數中改變a屬性的值時,原型上a屬性的值並不會改變。

__proto__和constructor

所有的對象上都有_prop_屬性。

  • 一般通過Object.getPrototypeOf(對象)來獲取一個對象的_prop_.
  • 一般通過Object.prototype.isPrototypeOf(對象)判斷當前對象是否在指定對象的原型鏈上。
  • 一般通過 對象 instanof 函數判斷函數的原型是否在對象的原型鏈上。在有iframe時不建議使用這種方法,因爲數組的指向會發生改變。
    舉例:
//判斷一個值是否爲數組   現在可以用Array.isArray()判斷。
Array.prototype.isPrototypeOf();
//第二種法
[] instanceof	Array          
  • 一般通過Object.prototype.hasOwnProperty(屬性名)判斷一個對象自身是否擁有某個屬性。

Object.create() 創建一個對象,該對象的_prop_屬性指向傳入該函數的參數。

所有的函數都有prototype屬性,值爲對象。

在每個對象的原型上都有兩個私有屬性_proto_constructor ,這兩個屬性會隨着原型鏈一直繼承。
_proto_:會沿着原型鏈向上查找,一直找到原型鏈的最頂端。
constructor:找到原型對應的構造函數。

繼承的幾種方式

	function Origin () {
	};
	function Target () {
	}

下文我們會用OriginTarget兩個函數做示例,默認 是Target繼承Origin

1 傳統模式- 原型鏈繼承

	function Father (name,age) {
		this.name = name;
		this.age = age;
	}
	Origin.propotype = new Father();
	Target.propotype = new Origin();
	var target = new target();

弊端:會繼承原型鏈上許多多餘的東西,比如我們只需要Target函數

2 通過call和apply的方式

	function Target (){
		Origin.call(this);//只在了new的時候纔有效
	}

弊端:每 new 一次都會call 一次,都會多執行一次Origin函數,造成性能與效率的浪費。並且不能繼承原型,繼承的是構造函數。

3 共享模式

	Target.propotype = Origin.propotype;

弊端:修改Target.propotype 的同時也會修改Origin.propotype
所有的_prop_最終都會指向Object.propotype,因此Target.propotypeOrigin.propotype都是引用值。
比如:

	Target.propotype.lastName = 'li';

此時打印Origin.propotype.lastName的值:

	console.log(Origin.propotype.lastName);

返回值爲:
"li"
通常在我們開發過程中較爲理想的狀態是:Origin的原型 可以繼承 Target原型 的方法和屬性,並且修改其中任何一個原型都不會互相影響,即上述操作的理想狀態爲: console.log(Origin.propotype.lastName),返回值爲‘undefined’
因爲,我們構建了新的模式 聖盃模式

聖盃模式

	var Star = function (){
	}
	
	var inhreit = (function (Target,Origin){
		var F = function(){} ;
		retutn function () {
			F.prototype = Origin.propotype;
			Target.prototype = new F();
			Target.prototype.constructor = Target;
		}	
	})

var obj = {};
Object.creat(obj);
Object.creat()方法將會創建一個對象,這個對象的prototype指向傳入的參數(這裏是
obj);

工廠模式

每個構造函數都相當於一個工廠,所有通過 new被創造的對象都擁有其構造函數的方法和屬性,我們又可以對每個對象擴展新的屬性,並且這些對象之間並不會互相影響,這樣就加工出許多相同的部件。當需要創造多個相同的實例時,可以利用構造函數的特性來開發。這種開發模式被稱爲“工廠模式”。

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