JavaScript 高级程序设计(第3版)笔记——chapter6:面向对象的程序设计
一.创建对象
- 工厂模式。使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。【问题:没有解决对象识别问题】
-
1 function createPerson(name, age) { 2 var o = new Object(); 3 o.name = name; 4 o.age = age; 5 o.sayName = function() { 6 console.log(this.name); 7 } 8 return o; 9 } 10 11 var p1 = createPerson("p1", "10"); 12 p1.sayName(); //p1 13 console.log(p1 instanceof Object); //true 14 console.log(p1 instanceof createPerson); //false
- 构造函数模式。可以创建自定义引用类型,可以像创建内置对象实例一样使用new操作符。缺点:每个成员都无法得到复用。
-
1 function Person(name, age) { 2 this.name = name; 3 this.age = age; 4 this.sayName = function() { 5 console.log(this.name); 6 } 7 } 8 var p2 = new Person("p2", 11); 9 p2.sayName(); //p2 10 console.log(p2 instanceof Object); //true 11 console.log(p2 instanceof Person); //true
- 原型模式。使用构造函数的prototype属性来指定那些应该共享的属性和方法。
-
1 function person(name) { 2 } 3 person.prototype.name = "person"; 4 person.prototype.sayName = function() { 5 console.log(this.name); 6 } 7 var p3 = new person(); 8 var p4 = new person(); 9 p3.sayName();//person 10 console.log(p3.sayName == p4.sayName);//true
- 组合使用构造函数模式和原型模式。使用构造函数定义实例属性,而使用原型定义共享的属性和方法。
-
1 function p(name) { 2 this.name = name; 3 } 4 p.prototype.sayName = function() { 5 console.log(this.name); 6 } 7 var p5 = new p("p5"); 8 var p6 = new p("p6"); 9 p5.sayName();//p5 10 p6.sayName(); //p6 11 console.log(p5 instanceof Object); //true 12 console.log(p5 instanceof p); //true 13 console.log(p5.constructor instanceof Function);//true
二.继承
- 通过原型链继承。
- 注意点1:使用字面量添加新方法会重写原型链。
1 function SuperType() { 2 this.property = true; 3 } 4 5 SuperType.prototype.getSuperValue = function() { 6 return this.property; 7 } 8 9 function SubType() { 10 this.subproperty = false; 11 } 12 13 //继承了SuperType 14 SubType.prototype = new SuperType(); 15 16 //使用字面量添加新方法,会导致上一行代码无效。因为这样重写了原型链 17 SubType.prototype = { 18 getSubValue : function() { 19 return this.property; 20 }, 21 22 someOtherMethod : function() { 23 return false; 24 } 25 }; 26 27 var instance = new SubType(); 28 console.log(instance.getSuperValue()); //error
- 注意点二:包含引用类型值的原型属性会被所有实例共享。
-
1 function SuperType() { 2 this.colors = [1,2,3]; 3 } 4 5 function SubType() { 6 } 7 8 SubType.prototype = new SuperType(); 9 var instance1 = new SubType(); 10 instance1.colors.push(4); 11 console.log(instance1.colors); //[ 1, 2, 3, 4 ] 12 13 var instance2 = new SubType(); 14 console.log(instance2.colors); //[ 1, 2, 3, 4 ]
- 借用构造函数。在子类型构造函数的内部调用超类型构造函数。
-
1 function SuperType() { 2 this.colors = [1,2,3]; 3 } 4 5 function SubType() { 6 SuperType.call(this); 7 } 8 9 SubType.prototype = new SuperType(); 10 var instance1 = new SubType(); 11 instance1.colors.push(4); 12 console.log(instance1.colors); //[ 1, 2, 3, 4 ] 13 14 var instance2 = new SubType(); 15 console.log(instance2.colors); //[ 1, 2, 3]
/*在新的SubType对象上执行SuperType()函数中定义的所有对象初始化代码。所以,SubType的每个实例就会具有自己的colors属性的副本了。*/ - 组合继承。使用原型链实现对原型属性和方法的继承。而通过借用构造函数来实现对实例属性的继承。这样,即通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
-
1 function Super(name) { 2 this.name = name; 3 this.num = [1,2,3]; 4 } 5 6 Super.prototype.SayName = function() { 7 console.log(this.name); 8 }; 9 10 function sub(name, age) { 11 //继承属性 12 Super.call(this, name); 13 this.age = age; 14 } 15 //继承方法 16 sub.prototype = new Super(); 17 sub.prototype.constructor = sub; 18 sub.prototype.SayAge = function() { 19 console.log(this.age); 20 } 21 22 var i1 = new sub("i1", 29); 23 i1.num.push(4); 24 console.log(i1.num);//[ 1, 2, 3, 4 ] 25 i1.SayAge(); //29 26 i1.SayName(); //i1 27 28 var i2 = new sub("i2", 27); 29 console.log(i2.num); //[ 1, 2, 3] 30 i2.SayAge(); //27 31 i2.SayName(); //i2