九、高级面向对象技术之继承

1.工厂函数模式创建对象

例如:



function factory(name,age){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.sayName = function(){

    };
    return obj;
}
var obj1 = factory("terry",12);
var obj2 = factory("larry",12);



此模式存在的问题有:对象类型无法细分;其中的函数会重复创建,浪费内存空间且破坏封装性。

 

2.构造函数模式创建对象

通过Object、Array、Date、Number、String、Boolean、RegExp等系统构造函数,或通过自定义构造函数,如function Student(){},创建对象。此模式解决了对象类型无法细分的问题,但仍未解决函数重复创建,破坏封装性的问题。

 

3.构造函数模式与原型相结合模式

此模式可将对象属性保存在相应实例中,而方法保存在实例的构造函数原型中,如:



function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function(){
console.log(“Hi, my name is” + this.name);
}
var p1 = new Person("terry",12);
var p2 = new Person("larry",13);



 

可用obj instanceof Function判断obj是否是Function的实例。

 

4.原型链继承

每个构造函数都有一个原型对象,原型对象中都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。当原型对象等于另外一个类型的实例即继承。调用某个方法或者属性的步骤。其核心在于:子构造函数的原型指向(是)父构造函数的实例,如Dog的原型Dog.prototype是Object的实例。

 

JavaScript脚本执行命令_javascript

再例如:



//定义父类类型
function Animal(){
    this.name = "animal"    
}
Animal.prototype.sayName = function(){
    console.log(this.name);
}
//定义子类类型
function Dog(){
    this.color = "灰色"
}
//通过将子对象的原型对象指向父对象的一个实例来完成继承
Dog.prototype = new Animal();
//区分父类实例的类型
Dog.prototype.constructor = Dog;    
//子对象的方法其实是定义在父类对象的实例上
Dog.prototype.sayColor = function(){
    console.log(this.color);
}
var dog = new Dog();
console.log(dog);    //Dog { color: '灰色' }
dog.sayColor();    //灰色
dog.sayName();    //animal



 

在子类构造函数内部调用超类构造函数可以简化其初始化过程,原理是使用原型链实现对原型属性和方法的继承,而通过借用构造函数实现对实例属性的继承,例如:



function Animal(name,age){
    this.name = name;
    this.age = age;
}
Animal.prototype.sayName = function(){
    console.log("my name is",this.name);
}
function Person(name,age,gender){
    Animal.call(this,name,age);
    this.gender = gender;
}
Person.prototype = new Animal();
Person.prototype.constructor = Person;        //替换原型
Person.prototype.sayGender = function(){
    console.log("my gender is",this.gender);
}
var p = new Person("terry",12,"male");
console.log(p);        //Person { name: 'terry', age: 12, gender: 'male' }
p.sayName();        //my name is terry
p.sayGender();        //my gender is male



 

子类型覆盖超类型中的某个方法,或者是需要添加超类中不存在的方法,都需要将给原型添加方法的代码放在继承之后(即替换原型的语句之后),且创建子类对象的操作也应在替换原型之后进行,否则会出现“同母异父”的情况,例如:



function Dog(name,age){
    this.name = name;
    this.age = age;
}
Dog.prototype.sayName = function(){
    console.log("hi, my name is",this.name);
}
var d1 = new Dog("一休",2);
console.log(d1);

Dog.prototype = {
    constructor:Dog,
    sayName:function(){console.log(this.name)},
    sayAge:function(){console.log(this.age);}
}
var d2 = new Dog("八哥",2);
console.log(d2);
console.log(d1.constructor === d2.constructor);    //true
console.log(d1.__proto__ === d2.__proto__);    //false


 

JavaScript脚本执行命令_JavaScript脚本执行命令_02