构造函数的继承

1.构造函数其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。

 
function Cat(name,color){
    this.name=name;
    this.color=color;
      this.type = "猫科动物";
      this.eat = function(){console.log("吃老鼠");};
  }
  var cat1 = new Cat("大毛","黄色");
  var cat2 = new Cat("二毛","黑色");
  console.log(cat1.name); // 大毛
  console.log(cat1.color); // 黄色
    //这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。
    console.log(cat1.constructor == Cat); //true
    console.log(cat2.constructor == Cat); //true
    //instanceof运算符,验证原型对象与实例对象之间的关系。
    console.log(cat1 instanceof Cat); //true
    console.log(cat2 instanceof Cat); //true

    console.log(cat1.type); // 猫科动物
    cat1.eat(); // 吃老鼠

这样写的弊端:对于每一个实例对象,type属性和eat()方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。


console.log(cat1.eat == cat2.eat); //false

所以对于相同的属性和方法等,要用prototype去定义。上面的那两个公共部分应该如下写:


  Cat.prototype.type = "猫科动物";
  Cat.prototype.eat = function(){console.log("吃老鼠")};

此时:


console.log(cat1.eat == cat2.eat); //true

其实这也是JavaScript继承机制的设计思想,所有实例对象需要共享的属性和方法,都放在prototype对象里面;那些不需要共享的属性和方法,就放在构造函数里面。

一些常用属性:


   console.log(Cat.prototype.isPrototypeOf(cat1)); //true
  console.log(Cat.prototype.isPrototypeOf(cat2)); //true

    //本地属性才为true,prototype继承的属性为false
  console.log(cat1.hasOwnProperty("name")); // true
  console.log(cat1.hasOwnProperty("type")); // false

  console.log("name" in cat1); // true
  console.log("type" in cat1); // true
    for(var prop in cat1) { //遍历属性,包括继承的
        console.log("cat1[" + prop + "]=" + cat1[prop]); 
    }

 

2.构造函数的继承

一、 构造函数绑定。使用call或apply方法,将父对象的构造函数绑定在子对象上。


    function Animal(){
    this.species = "动物";
  }
  function Cat(name,color){
    Animal.apply(thisarguments);
    this.name = name;
    this.color = color;
  }
  var cat1 = new Cat("大毛","黄色");
  console.log(cat1.species); // 动物

二、 prototype模式

 
 function Animal(){
    this.species = "动物";
  }
  function Cat(name,color){
    this.name = name;
    this.color = color;
  }
    console.log(Cat.prototype); //Object
    Cat.prototype = new Animal();
    console.log(Cat.prototype); //Animal

    //Cat的prototype对象指向一个Animal的实例,所以Cat也拥有constructor属性
    console.log(Cat.prototype.constructor);//function Animal(){this.species = "动物";}
    console.log(Cat.prototype.constructor == Animal);//true
    Cat.prototype.constructor=Cat;//如果没有这一句,cat1的构造函数就是上面的Animal,所以要把它更正为Cat
    console.log(Cat.prototype.constructor);//function Cat(name,color){this.name = name;this.color = color;}

  var cat1 = new Cat("大毛","黄色");
    console.log(cat1.species); // 动物
   console.log(cat1.constructor); //function Cat(name,color){this.name = name;this.color = color;}


    //也就是说,当替换了prototype对象
    //o.prototype = {};
    //必须要修正constructor
    //o.prototype.constructor = o;

 

前面两种方法是把属性直接定义在构造函数里,一般公共属性的话一般放在prototype,继承的方式如下

三、 直接继承prototype(不够完善)


 function Animal(){}
    Animal.prototype.species = "动物";
    function Cat(name,color){
    this.name = name;
    this.color = color;
  }
  Cat.prototype = Animal.prototype;
  Cat.prototype.constructor = Cat;
  var cat1 = new Cat("大毛","黄色");
  console.log(cat1.species); // 动物
    console.log(Cat.prototype.constructor);//function Cat(name,color){this.name = name;this.color = color;}
    console.log(Animal.prototype.constructor);//function Cat(name,color){this.name = name;this.color = color;}这样很混乱
    //与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。
    //缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,Cat.prototype与Animal.prototype永远保持一致,属性也是。

四、 利用空对象作为中介


    function Animal(){}
    Animal.prototype.species = "动物";
    function Cat(name,color){
    this.name = name;
    this.color = color;
  }
  function extend(ChildParent) {  //封装好
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();  //用空对象作为中介,避免了直接继承的弊端
    Child.prototype.constructor = Child;
    //Child.uber = Parent.prototype;//使之可以调用父对象的方法,实现继承的完备性
  }
    extend(Cat,Animal);
  var cat1 = new Cat("大毛","黄色");
  console.log(cat1.species); // 动物

五、 拷贝继承


   function Animal(){}
    Animal.prototype.species = "动物";
    function Cat(name,color){
    this.name = name;
    this.color = color;
  }
  function extend2(ChildParent) {//封装好
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
            console.log(i);
            console.log(p[i]);
      c[i] = p[i];
    }
    //c.uber = p;
  }
   extend2(CatAnimal);
  var cat1 = new Cat("大毛","黄色");
  console.log(cat1.species); // 动物

 

posted @ 2017-03-15 21:49  森森森shen  阅读(333)  评论(0编辑  收藏  举报