哇哦~今天迎來的是掘金後臺編寫文章的新頁面,不知道這個頁面是須要經過寫文章才能打開的,仍是新上的啊哈哈啊哈javascript
其實本身平時在總結上是很是注重的,可是通常是總結的比較隨意,會存放在本身的筆記軟件中,推薦使用「語雀」,劃分目錄和頁面的美觀交互深得我心,固然,適合本身的一個筆記軟件纔是最重要的;接下來的半個月內,我也將從新回顧本身總結的知識點和項目中遇到的困難點,並整理到掘金文章中html
談起對象,實際上是一個很需的概念,在大學課程java
學習中就留下了一個很是清晰的詞語「面向對象」編程,對於對象而言,不只僅是去建立、去繼承,與之相呼應的還有一些理論性的名詞,這些名詞在javascript
中多是不全體現的,更多體如今java語言程序中;java
我忽然想起大學考試卷子填寫概念的場景了 🤯🤯🤯typescript
所謂對象,本質上就是指事物(包括人和物)在程序設計語言中的表現形式。這裏的事物能夠是任何的東西(如客觀存在的對象,或者較爲抽象的概念);
好比 小狗,咱們將其理解成對象,它是具備某些明確的特徵的(體重、顏色、名字等),除此以外,還可以執行某些動做(汪汪叫、吃飯、睡覺等),在javascript
語言中這些明確的某些特徵就是屬性
,可以執行的行爲就是方法
。編程
類就是具有某些共同特徵的實體的集合,它是一種抽象的數據類型,它是對所具備相同特徵實體的抽象。在面向對象的程序設計語言中,類是對一類「事物」的屬性與行爲的抽象。
好比:「老人」、「兒童」、「青年「、「中年人「是關於人的年齡層段的劃分,他們的共有的某些特徵,其實能夠抽成「人」,segmentfault
在傳統的OOP環境中,繼承一般指的是類與類之間的關係,但因爲javascript
中不存在類,所以它的繼承只能發生在對象之間;
當一個對象繼承自另外一個對象時,一般會往其中加入新的方法,以擴展被繼承的老對象。一般將這一過程稱之爲「B繼承自A」或「B擴展自A」。另外對於新對象來講,它能夠根據本身的須要,從繼承的那組方法中選擇幾個來從新定義。這樣作並不會改變對象的接口,由於其方法名是相同的,只不過當調用新對象時,該方法的行爲與以前不一樣了markdown
封裝主要用於闡述對象中所包含的內容。封裝概念一般由兩部分組成:app
封裝的目的是將信息隱藏,即方法與屬性的可見性。通常而言,封裝包括封裝數據和封裝實現 在許多語言的對象系統中,封裝數據是由語法解析來實現的,這些語言提供了public、private、protected
這些關鍵字來限定方法和屬性的可見性,這種限定分類定義了對象用戶所能訪問的層次; 但javascript
並無提供對這些關鍵字的支持,只能依賴變量的做用域來實現封裝特性, 並且只能模擬出 public 和 private
這兩種封裝性。除了ECMAScript6
中提供的let以外,通常經過函數來建立做用域:不過typescript就另當別論了;ide
多態的實際含義是:同一個操做做用於不一樣的對象上面,能夠產生不一樣的解釋和不一樣的執行結果。換句話說,給不一樣的對象發送同一個消息的時候,這些對象會根據這個信息分別給出不一樣的反饋; 本身停留理解不夠深入,就不班門弄斧了,直接推薦連接閱讀函數
javascript
的繼承方式也有不少種,平常經常使用的方法也是很是多,而且不少書籍中,也有介紹繼承的方法,本文參考《javascript 高級程序設計(第三版)》
在咱們瞭解的JavaScript
中,對於原型鏈的使用是很是多的,被建立的對象能夠經過原型鏈訪問上級的對象,而原型鏈繼承的方式正式運用了此訪問關係;
function Super() {
this.value = true;
}
Super.prototype.getValue = function () {
return this.value;
}
function Sub() { }
console.log("super", new Super())
//Sub繼承super
Sub.prototype = new Super();
//將sub的構造函數指向 Sub
Sub.prototype.constructor = Sub;
//建立實例
var instance = new Sub();
console.log('sub', instance)
console.log(instance.getValue())
複製代碼
而sub
、Super
以及instance
之間關係是:
原型鏈最主要的問題在於包含引用類型值的原型屬性會被全部實例共享,而這也正是爲何要在構造函數中,而不是在原型對象中定義屬性的緣由。 在經過原型來實現繼承時,原型實際上會變成另外一個類型的實例。因而,原先的實例屬性也就瓜熟蒂落地變成了如今的原型屬性了;
構造函數包含引用類型
function Super1() {
this.colors = ['red', 'blue', 'green'];
}
function Sub1() { };
//Sub繼承了Super
Sub1.prototype = new Super1();
var instance1 = new Sub1();
//查看instance1中的屬性
console.log('instance1',instance1)
instance1.colors.push('black');
console.log('instance1.colors',instance1.colors);//'red,blue,green,black'
var instance2 = new Sub1();
console.log('instance2 經過Sub1構造出來的',instance2.colors);//'red,blue,green,black'
複製代碼
藉助原型能夠基於已有的對象來建立新對象,同時沒必要所以建立自定義類型;
具體的實現方式;
function object(o) {
function F() { };
F.prototype = o;
return new F();
}
var superObj = {
init: function (value) {
this.value = value;
},
getValue: function () {
return this.value;
}
}
var subObj = object(superObj);
console.log('subObj',subObj)
subObj.init('sub');
console.log('subObj.getValue',subObj.getValue());//'sub'
複製代碼
與原型鏈繼承的關係;它們的一個重要區別是父類型的實例對象再也不做爲子類型的原型對象
; 這種方式更相似於Object.create()
的實現
function Super(){
this.value = 1;
}
Super.prototype.value = 0;
function Sub(){};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
//建立子類型的實例對象
var instance = new Sub;
console.log(instance.value);//0
複製代碼
function F(){};
F.prototype = Super.prototype;
Sub.prototype = new F();
複製代碼
由上面代碼看出,子類的原型對象是臨時類F的實例對象,而臨時類F的原型對象又指向父類的原型對象;因此,實際上,子類能夠繼承父類的原型上的屬性,但不能夠繼承父類的實例上的屬性
; 原型繼承和原型鏈繼承都是共享父例引用類型的值;
function object(o) {
function F() { };
F.prototype = o;
return new F();
}
var superObj = {
colors: ['red', 'blue', 'green']
};
var subObj1 = object(superObj);
subObj1.colors.push("black");
var subObj2 = object(superObj);
subObj2.colors.push("white");
console.log('superObj.colors',superObj.colors);
console.log('subObj1.colors',subObj1.colors);
複製代碼
借用構造函數,很是深入明瞭了,實際上是藉助super的屬性,即在子類型構造函數的內部調用超類型構造函數,經過使用apply()和call()方法在新建立的對象上執行構造函數;
//借用構造函數
function Super2() {
console.log("Super2執行了")
this.colors = ['red', 'blue', 'green'];
}
function Sub2() {
//繼承了Super
Super2.call(this);
}
var instance2 = new Sub2();
instance2.colors.push('black');
console.log('instance2.colors',instance2.colors);// ['red','blue','green','black']
var instance3 = new Sub2();
console.log('instance3.colors',instance3.colors);// ['red','blue','green']
複製代碼
此時咱們的引用類型也不會存在衝突啦,這個主要的緣由仍是由於當咱們Sub2中執行的時候,Super2
的當前執行做用域在Sub2中,造成了內部的變量關係;
Super2
中的原型上的方法是沒法繼續使用的借用構造函數可以幫助咱們解決對象引用
問題,原型鏈繼承可以幫助咱們解決調用原型方法問題,若是將這兩種方式組合在一塊兒;豈不美哉~ 原型鏈繼承+借用構造函數繼承=既能夠獲取構造函數中的方法,也可以斷引用;
組合繼承(combination inheritance)
有時也叫僞經典繼承,指的是將原型鏈和借用構造函數的技術組合到一塊,從而發揮兩者之長的一種繼承模式。其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數來實現對實例屬性的繼承。這樣,既經過在原型上定義方法實現了函數複用,又可以保證每一個實例都有它本身的屬性;
var count = 0; //用於計數
function Super(name) {
console.log('Super==count',count++)
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Super.prototype.sayName = function () {
console.log('Super==this.name',this.name);
};
function Sub(name, age) {
console.log('Sub==count',count++)
// 第二次調用Super(),Sub.prototype又獲得了name和colors兩個屬性,並對上次獲得的屬性值進行了覆蓋
Super.call(this, name);
this.age = age;
}
//繼承方法
// 第一次調用Super(),Sub.prototype獲得了name和colors兩個屬性
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
Sub.prototype.sayAge = function () {
console.log('Sub===this.age',this.age);
}
var instance1 = new Sub("bai", 29);
instance1.colors.push("black");
console.log('instance1.colors',instance1.colors);//['red','blue','green','black']
instance1.sayName();//"bai"
instance1.sayAge();//29
console.log('Super',new Super())
複製代碼
Super
中引用類型數據獨立Super
中傳入自定義的參數Super
調用次數問題,繼承時候調用一次,實例化Sub
後再次調用了Super
Sub
的時候都會調用Super.call
寄生組合式繼承帶來的影響須要調用兩次Super。寄生組合式繼承與組合繼承類似,都是經過借用構造函數來繼承不可共享的屬性,經過原型鏈的混成形式來繼承方法和可共享的屬性。只不過把原型繼承的形式變成了寄生式繼承。使用寄生組合式繼承能夠沒必要爲了指定子類型的原型而調用父類型的構造函數
寄生式繼承
只繼承了父類型的原型屬性,而父類型的實例屬性是經過借用構造函數的方式來獲得的;也就是 咱們借用Super
的構造函數,可是去複製Super
的原型函數;
function Super(name) {
console.log("Super === 執行")
this.name = name;
this.colors = ["red", "blue", "green"];
}
Super.prototype.sayName = function () {
console.log("this.name",this.name)
return this.name;
};
function Sub(name, age) {
//第一次 借用構造函數
Super.call(this, name);
this.age = age;
}
//繼承的方法 就是拷貝原型
if (!Object.create) {
Object.create = function (proto) {
function F() { };
F.prototype = proto;
return new F();
}
}
// 利用複製原型的方式進行操做 將Super.prototype的原型方法經過實例化給Sub
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
var instance1 = new Sub("bai", 29);
instance1.colors.push("black");
console.log('instance1.colors',instance1.colors);//['red','blue','green','black']
instance1.sayName();//"bai"
var instance2 = new Super("hu", 27);
console.log("instance2.colors",instance2.colors);//['red','blue','green']
instance2.sayName();//"hu"
複製代碼
這三者的鏈式關係
ps:很久以前整理的,查過不少文檔博客內容,可是沒有一一記錄下來,我仍是很尊重知識來源的的🥳🥳