JScript创建对象与继承方式--红宝书第六章

一. 创建对象
1. 工厂模式
解决了创建多个类似对象的问题,但是通过工厂模式创建的对象无法识别是一个什么样的对象类型

function objFactory(name,age){
       var  o = new Object();  //适合于原生构造函数创建实例
       o.name=name;
       o.age=age;
       o.getAction=function(){console.log(this.name)};
       return o;
}
var person1=objFactory("jasson",10);
var person2=objFactory("jim",8);

2. 构造函数模式

//自定义一类特性的类型
function  Animal(name,age){
        this,name=name;
        this.age=age;
        this.getAction=function(){
               console.log(this.name);
        }
}
var dog = new Animal("DOG",3);
var  cat=new Animal("cat",2);

构造函数可以用于创建特定类型的对象。除了Object、Array原生构造函数,还可以自定义构造函数。自定义构造函数可以用于将它的实例标识为一种特定的类型,如Dog、Cat。
问题:每个方法都会在每个实例上创建一遍。在ECMAscript中函数是对象,每定义一个函数相当于实例化了一个Function对象
即 this.getAction=function(){……}
逻辑上等价于 this.getAction=new Function(){……}
所以不同实例上的同名函数是不相等的如下:

console.log(dog.getAction==cat.getAction);
VM649:1 false

但是,创建两个可以完成同样任务的Function实例是没有必要的。大可将函数移到构造函数体外去,如下:

function  Animal(name,age){
        this,name=name;
        this.age=age;
 //此时this.getAction属性设为等于全局函数getAction,而getAction是一个指向函数的指针,因此解决了两个函数做同一件事的问题。
        this.getAction=getAction; 
}
function getAction(){
               console.log(this.name);
        }
var dog = new Animal("DOG",3);
var  cat=new Animal("cat",2);

问题:如果对象需要定义很多方法,那么会存在很多全局函数,那么自定义引用类型的封装性无法得以体现了。这一点可以用原型模式解决。

3. 原型模式
可以让所有对象实例共享它所包含的属性和方法。

function  Animal(){
}
Animal.prototype.name="dog";
Animal.prototype.age=2;
**Animal.prototype.getAction=function(){
               console.log(this.name);
        }**
var dog = new Animal();
var  cat=new Animal();

4. 组合构造模式
构造函数模式+原型模式的方法
使实例可以拥有各自的实例属性,而原型模式可以用于定义共同的属性和方法。

function  Animal(name,age){
        this,name=name;
        this.age=age;
        }
        *Animal.prototype.getAction=function(){
               console.log(this.name);
        }
        var dog = new Animal("DOG",3);
        var  cat=new Animal("cat",2);

5. 动态原型模式
将所有信息封装在构造函数中,在必要情况下初始化原型。

function  Animal(name,age){
        this,name=name;
        this.age=age;
       
        **if(typeof this.getAction != "function"){
             Animal.prototype.getAction=function(){
               console.log(this.name);
           }
      }**
 }
        var dog = new Animal("DOG",3);
        var  cat=new Animal("cat",2);
        dog.getAction();

6. 寄生构造函数

function  Animal(name,age){     //寄生的宿主构造函数
        var o= new Object();   //寄生者
       o.name=name;
       o.age=age;
       o.getAction=function(){console.log(this.name)};
       return o;
}
var dog = new Animal("DOG",3);
var  cat=new Animal("cat",2);

二. 继承

实例、构造函数、实例的关系
在这里插入图片描述

1. 原型链继承
定义一个父类Animal

function Animal(){
      this.name="animal";
}
Animal.prototype.getName=function(){return this.name};
//定义子类
function Dog(){
     this.age=2;
}
Dog.prototype = new Animal(); //原型继承
var instance = new Dog();   //子类的实例
alert(instance.getName());    //输出为animal,继承了父类的方法
console.log(instance.constructor==Animal);    //VM2342:1 true, 

使用原型继承后,instance.constructor会指向父类Animal,因为Dog.prototype指向了Animal的原型,所以constructor指向了animal。
问题:1.创建子类型的实例时,无法在不影响其他对象实例的情况下向超类型的构造函数传递参数。2.无法实现多继承
特点:1.简单易于实现

2. 借用构造函数继承

function Animal(){
      this.names=["animal"];
}
function Dog(){
   **Animal.call(this);**     // 借调了父类的构造函数
}
 //每当创建一个实例时,都会利用call方法借调animal的构造函数,在实例对象上会执行animal构造函数中定义的初始化代码,因此Dog的每个实例上都会有names属性的副本。所以instance1和instance1的names打印出来结果会不一样
var instance1 = new Dog();  
instance1.names.push("dog");
console.log(instance1.names);   //(2) ["animal", "dog"]

var instance2 = new Dog();
console.log(instance2.names);  //VM2406:12 ["animal"]

借用构造函数的另一点----子类型构造函数可以向父类构造函数传递参数

function Animal(name){
      this.names=name;
}
function Dog(){
   **Animal.call(this,"dog");**  // 借调了父类的构造函数同时传递参数
   this.age=2;
}
var instance = new Dog();
console.log(instance.name);  //VM2406:12  "dog"

问题:1.函数无法复用。因此需要用组合继承 。 2.只能继承父类的实例和方法,无法继承原型属性和方法
特点:1.可以实现多继承。2.创建子类实例时可以向父类传参

3. 组合继承
借用构造函数继承+原型继承

function Animal(name){
      this.name=name;
      this.colors=["red","blue","green"];
}
Animal.prototype.getName=function(){
      console.log(this.name);
}
function Dog(name,age){
     Animal.call(this,name);    //**第二次调用超类animal的构造函数**
     this.age=age;
}
Dog.prototype=new Animal();   //**第一次调用超类animal构造函数**
Dog.prototype.constructor=Dog;  //使得dog.prototype.constructor仍然指向dog
Dog.prototype.getAge=function(){console.log(this.age);};

var instance1 = new Dog("JIM",2);
instance1.colors.push("yellow");  
console.log(instance1.colors);  //(4) ["red", "blue", "green", "yellow"]
instance1.getName();  // JIM
instance1.getAge();  //2

var instance2 = new Dog("tom",11);
console.log(instance2.colors);  //VM2911: (3) ["red", "blue", "green"]
instance2.getName();  // tom
instance2.getAge();  //11

如果注释掉Dog.prototype.constructor=Dog; 这句,那么
console.log(Dog.prototype.constructorDog);.//false
console.log(Dog.prototype.constructor
Animal); //true

问题:1.无论什么情况下,都会调用两次超类的构造函数,导致有两组超类中的属性name和colors,一组在实例上,一组在Dog原型中。------解决方案为寄生组合式继承
特点:1.可以继承父类的属性方法,也可以继承原型属性方法。2.可以传参 。 3.函数可以复用

4. 寄生式继承
利用createAnimal()函数封装继承过程,类似于工厂模式和寄生构造函数的思维。

function createAnimal(original){
      var  o=new Object(original);   //original初始化的参数
      o.getName=function(){console.log(original.name);};
      return o;
}
var animal={
    name: "JIm",
    colors: ["red","bluer"]
};
var obj = createAnimal(animal);   //利用函数封装继承过程,返回的结果是个对象
obj.getName();  //JIM

5. 寄生组合式继承
寄生式继承+组合式继承
通过借用构造函数继承属性,利用原型链的混成形式继承方法。

//借用构造函数方法
function Animal(name){
      this.name=name;
      this.colors=["red","blue","green"];
}
Animal.prototype.getName=function(){
      console.log(this.name);
}
function Dog(name,age){
     Animal.call(this,name);    //**第二次调用超类animal的构造函数**
     this.age=age;
}
Dog.prototype.getAge=function(){
        console.log(this.age);
  };
//寄生组合继承的重点!!!!!
function inheritPrototype(dog, animal){
      var o = new Object(animal.prototype);
      o.constructor = dog;
      dog.prototype = o;
}
inheritPrototype(Dog,Animal);

var instance1 = new Dog("JIM",2);
console.log(instance1.colors);  // ["red", "blue", "green"]
instance1.getName();  // JIM
instance1.getAge();  //2

重点部分!!!
**function inheritPrototype(dog, animal){

var o = new Object(animal.prototype);
o.constructor = dog;
dog.prototype = o;
}
inheritPrototype(Dog,Animal);**
问题:1. 实现较为复杂
特点: 1.整体实现较为理想

猜你喜欢

转载自blog.csdn.net/Qian_mos/article/details/84728524