function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
複製代碼
但這種方式有一個缺點:沒法判斷某個對象是什麼類型。es6
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var p1 = new Person("Nicholas", 29, "Software Engineer");
var p2 = new Person("Greg", 27, "Doctor");
複製代碼
構造函數也存在問題,每一個方法都要在實例上建立一遍。也就是說p1和p2的sayName()方法雖然做用相同,但這兩個方法並非同一個函數bash
解析一道題函數
new操做符作了什麼:ui
(1)建立一個新對象this
(2)將構造函數的做用域賦給新對象(所以this就指向了這個新對象)spa
(3)執行構造函數中的代碼prototype
(4)返回新對象設計
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
複製代碼
當咱們改變 值爲引用類型的對象的屬性 時,這個改變的結果會被其餘對象共享。3d
構造函數模式的屬性沒毛病。缺點是:沒法共享方法code
原型模式的方法沒毛病。缺點是:當原形對象的屬性的值爲引用類型時,對其進行修改會反映到全部實例中
那咱們就將二者的結合,對象的屬性使用構造函數模式建立,方法則使用原型模式建立
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
複製代碼
JavaScript中引入了原型鏈的概念,具體思想: 子構造函數的原型對象初始化爲父構造函數的實例,孫構造函數的原型對象初始化爲子構造函數的實例…… ,這樣子對象就能夠經過原型鏈一級一級向上查找,訪問父構造函數中的屬性以及方法。
function SuperType(){
this.property = true;
};
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
};
// 繼承Supertype
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());
複製代碼
當咱們改變 值爲引用類型的原型對象的屬性 時,這個改變的結果會被全部子對象共享。這個缺點某些時候至關致命,因此咱們不多使用這種方法來繼承
function SuperObject(){
this.colors = ['red','blue'];
this.sayBye= function(){
console.log('Bye')
}
}
function SubObject(){
SuperObject.call(this); // 在子類中調用父類的構造方法,實際上子類和父類已經沒有上下級關係了
}
var instance1 = new SubObject();
instance1.colors.push('yellow');
var instance2 = new SubObject();
console.log(instance2.colors); //['red','blue']
console.log(instance2 instanceof SuperObject); // false
console.log(instance1.sayBye === instance2.sayBye) // false
複製代碼
這個方法雖然彌補了原型鏈的缺點,可是又暴露出了新的缺點:
1 子類和父類沒有上下級關係,instance2 instanceof SuperObject 結果是false
2 父類中的方法在每一個子類中都會生成一遍,父類中的方法沒有被複用。
組合繼承就是將原型鏈繼承和借用構造方法繼承組合,發揮二者之長。
function SuperType(name){
this.name = name;
this.colors = ['blue'];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name, age){
// 引用父類型的屬性,又調用了一次父函數
SuperType.call(this,name);
this.age = age;
}
// 繼承父類型的方法,調用了一次父函數
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType('zz',18);
instance1.sayName(); //zz
instance1.sayAge(); //18
instance1.colors.push('red');
console.log(instance1.colors); // ['blue','red']
var instance2 = new SubType('tt',22);
console.log(instance2.colors); // ['blue']
組合繼承會調用兩次父類型函數
原型式繼承
代碼塊
function object(o){
function F(){};
F.prototype = o;
return new F();
}
var Person = {
name: 'Nicholas'
friends: ['zz','cc']
}
var anotherPerson = object(Person);
anotherPerson.friends.push('dd');
console.log(anotherPerson.friends); //['zz','cc','dd']
複製代碼
function createAnother(o){
var clone = object(o);
o.sayHi = function(){
console.log('hi');
}
return clone;
}
複製代碼
雖然組合繼承沒啥大缺點,可是愛搞事情的有強迫症的程序猿們以爲,組合繼承會調用兩次父類型函數(在上面的代碼中標註了),不夠完美。因而道格拉斯就提出了寄生組合繼承。
思路是構造一箇中間函數,將中間函數的prototype指向父函數的原型對象,將子函數的prototype指向中間函數,並將中間函數的constructor屬性指向子函數。
function object(o){
function F(){};
F.prototype = o;
return new F();
}
function inheritPrototype(subType,superType){
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
function SuperType(name){
this.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function(){
alert(this.age)
}
var instance1 = new SubType('zz', 18);
instance1.sayName();
複製代碼
MDN:developer.mozilla.org/zh-CN/docs/…
JS高級語言程序設計第六章(面向對象的程序設計)