js基礎之阮一峰的面向物件程式設計
一 原型
1.複用:面對物件
面向物件程式設計是class來實現物件(類-介面)的繼承,js則是通過“原型物件”.
public class Person { int age; public Person(int a){ age=a; } void speak(){ System.out.println("今年我"+this.age+"歲"); } }
很重要的一個方面,就是物件的繼承,這對於程式碼的複用是非常有用的。
function Person(name){ this.name=name; this.sum=function(){ alert("this.name") } }
2.建構函式的缺點:無法共享
JavaScript 通過建構函式生成新物件,因此建構函式可以視為物件的模板
建構函式繼承的缺點:
二個例項,擁有的方法也變成二個了,浪費系統資源。方法是共享的,應該也共享。
這個問題的解決方法,就是 JavaScript 的原型物件(prototype)。
js中繼承機制的思想:是所有的方法和變數都可以共享。定義在原型上就可以共享。
js中函式的原型屬性都指向一個物件。
function Dog(name, age) { this.name = name; this.age = age; this.log = function () { console.log(this.name + ":" + this.age); }} let dog1 = new Dog("小黃", 5); let dog2=new Dog("小花",6);
對普通的函式沒有作用,對建構函式有作用。在外面用上prototype,原型屬性和方法。原型物件的屬性不是例項物件的屬性。
二 原型鏈
所有物件都有自己的原型鏈,一個物件可充當的其他物件的原型; 原型物件也是物件,也有自己的原型。因此形成原型鏈“prototype Chain”
一層層追溯到最頂層就是Object.prototype,所有物件都繼承了Object.prototype
的屬性。這就是所有物件都有valueOf
和toString
方法的原因
Object.prototype的原型是null,沒有任何屬性和方法。
“覆蓋”:讀取物件的某個屬性時,JavaScript 引擎先尋找物件本身的屬性,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的Object.prototype
還是找不到,則返回undefined
。
如果物件自身和它的原型,都定義了一個同名屬性,那麼優先讀取物件自身的屬性,這叫做“覆蓋”(overriding)。
缺點:一級級查詢,找不到,會遍歷整個原型鏈,那麼很影響屬性。
三 constructor屬性
prototype
物件有一個constructor
屬性,預設執行原型物件所在的建構函式。因在原型上,那麼構造可以被所有物件繼承。
function f(){}
var f=new f();
f.prototype.constructor===f f.hasOwnProperty(constructor)
f 是 建構函式f 的 例項物件, f 本身沒有construct。
修改原型的屬性或方法時,同時也要修改constructor,不然導致這個屬性不再指向Person
。由於Person
的新原型是一個普通物件,而普通物件的contructor
屬性指向Object
建構函式,導致Person.prototype.constructor
變成了Object
。
下面程式碼中,要麼將constructor
屬性重新指向原來的建構函式,要麼只在原型物件上新增方法,這樣可以保證instanceof
運算子不會失真。
C.prototype = {
constructor: C,
method1: function (...) { ... },
// ...
};
// 更好的寫法
C.prototype.method1 = function (...) { ... };
四 面試題
1.原型繼承
B繼承A,先有A與B,(就是先生成function A(){});
缺點:新例項無法向父類建構函式傳參。
B.prototype=new A(); let newB=new B();
2.call借用建構函式構成
在子元素的裡面寫上
fu.call(this,name),
3.組合繼承
引用自:https://javascript.ruanyifeng.com/oop/prototype.html#toc1