JS的继承

拖了很久的JS继承终于来个总结了T^T

本篇文章参考阮一峰老师的博文。一共有三篇。

一、先说一下prototype对象

function Cat(name, age){
    this.name = name;
    this.age = age;
    this.speak = function () {
        console.log(this.name + ' miao');
    }
}

var cat1 = new Cat('Tom', 1);
var cat2 = new Cat('John', 2);
console.log(cat1.speak());    // Tom miao
console.log(cat2.speak());    // John miao

上面代码中的两个实例,cat1 和 cat2 都有自己的name属性,age属性,speak方法,但是其实speak方法实可以共用的,这样就会造成了资源浪费。避免这种浪费,我们可以把 speak 方法写入构造函数的 prototype 对象中。

function Cat(name, age){
    this.name = name;
    this.age = age;
}

Cat.prototype.speak = function(){
    console.log(this.name + ' miao');
}

var cat1 = new Cat('Tom', 1);
var cat2 = new Cat('John', 2);

将可以共享的方法挂载在原型对象上,就可以避免出现内存浪费的现象了

Cat.prototype.speak = function() {
    console.log(this.name + ' miao');
}

Cat.prototype.eat = 'fish';

cat2.prototype.eat = 'meat';


// 问题来了,如果我改变其中一个实例的原型上的属性和方法,那么另一个原型会不会收到影响呢

答案是不会!!!

 

 

 但是,如果修改的是 cat2.__proto__.eat,那么就会对 cat1 有影响了

 

 

 这里可能有点迷!!!是的,我有点迷~~~~~~~

我是这样子理解的

因为创建实例需要用到 new 操作符,那么 new 中间作了什么妖呢

  • 创建了一个新对象
  • 将新对象的__proto__属性指向构造函数的原型对象,新对象就新增了构造函数原型对象上的属性和方法
  • 将构造函数的this指向替换成新对象,再执行构造函数,这样新对象就新增了构造函数本地的属性和方法了
    // 模拟 new
    var obj = {};
    obj.__proto__ = 构造函数.prototype;
    构造函数.apply(obj);

     

那么看会又来的构造函数 Cat,我画了这样一幅图

 

 

二、JS继承

  1. 原型链继承——将父类的实例作为子类的原型
    function Animal(name){
        this.name = name;
    }
    Animal.propotype = {
        canRun: function(){
            console.log(this.name + ' can run.');
        }
    }
    function Cat(){
        this.speck = 'miao';
    }
    Cat.prototype = new Animal('Tom');
    Cat.prototype.constructor = Cat;

    我觉得应该会有人有和我一样的疑惑。为什么会有Cat.prototype.constructor = Cat的出现。

     因为我们把父类Animal的实例作为了子类Cat的原型对象,因此如果没有Cat.prototype.constructor = Cat,Cat.prototype.constructor就会指向Animal,造成继承链的混乱,所以我们需要手动纠正。

    2. 构造继承——改变this的指向,用apply或者call方法实现

    

function Animal(name){
    this.name = name;
}
Animal.prototype = {
    canRun: function(){
        console.log(this.name + ' it can run!');
    }
}
function Cat(name){
    Animal.call(this, name);
    this.speak = 'miao';
}
var cat1 = new Cat('Tom');

    这个继承方法有一个不好,就是子类无法继承父类原型上的属性和方法,也就是说 cat1.canRun()会出错。

 

 

         3. 组合继承——将原型链继承和构造继承结合到一块

    

function Animal(name){
    this.name = name;
}
Animal.prototype = {
    canRun: function(){
        console.log(this.name + 'is can run!');
    }
}
function Cat(name, age){
    Animal.call(this, name);
    this.speak = 'miao';
    this.age = age;
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat('Tom', 12);

 

posted @ 2019-09-17 22:28  瓶子咕咕咕  阅读(151)  评论(0编辑  收藏  举报