javascript继承分析

一,传统JS继承方法:

  1,原型式继承:

    

//声明父类
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 给父类添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

//实例化父类
var person = new Person('zhl',30);
//调用父类方法
person.sayName();  // zhl

// 声明子类
function Worker(name,age,work){
    this.name = name;
    this.age = age;
    this.work = work;
}
//原型式继承  其实就是子类的原型指向父类的一个实例
Worker.prototype = new Person();
//给子类添加方法
Worker.prototype.sayWork = function(){
    console.log(this.work);
}

//实例化一个子类
var worker = new Worker('vsmart',32,'itcoder');
//调用子类方法
worker.sayName();  // vsmart
worker.sayWork(); // itcoder

  貌似可以用了,不要高兴太早,这里是有很大的坑的!

  此继承方法有几个弊端:

  1,声明父类与子类的构造函数中有很多重复的初始化赋值;

  2,实例化子类的对象 flag 属性竟然是 true

    然而这个属性本身子类并没有初始化,哪来的?

    console.log(worker.flag) //true
    console.log(Worker.prototype.flag) //true

    哦,原来是从子类的原型上查找到的,也就是从父类的一个实例上获取到的;

    本来我们要做到 属性与方法分离的,现在呢,这个属性竟然在原型上,原型应该只放方法才对。

  3,子类的构造函数 constructor 竟然指向了 父类的 constructor,这个指向错误将来势必会带来耦合

    console.log(worker.constructor)  //

function Person(name,age){
    this.name = name;
    this.age = age;
    this.flag = true;
}

  综合以上几点我们要做优化;

  1,我们可以借用父类的构造函数初始化子类的构造函数  利用 apply 或 call 改变指向

  2,我们要重新改变子类的构造函数指向

  

//声明父类
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 给父类添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

//实例化父类
var person = new Person('zhl',30);
//调用父类方法
person.sayName();  // zhl

// 声明子类
function Worker(name,age,work){
    Person.apply(this,arguments);  // 借用父类构造方法
    this.work = work;
    this.flag = false;
}
//原型式继承  其实就是子类的原型指向父类的一个实例
Worker.prototype = new Person();
//给子类添加方法
Worker.prototype.sayWork = function(){
    console.log(this.work);
}
//改变constructor指向
Worker.prototype.constructor = Worker;

//实例化一个子类
var worker = new Worker('vsmart',32,'itcoder');
//调用子类方法
worker.sayName();  // vsmart
worker.sayWork(); // itcoder

console.log(worker.flag) //false    //子类自己的属性
console.log(Worker.prototype.flag)  //true  从子类原型上查找
console.log(worker.constructor) //正确指向自己的构造方法

  function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
  }



   2,混合拷贝继承:

     所谓混合拷贝继承是指,构造函数还是借用父类的方式,但方法继承就是模拟拷贝的方式,

    

//声明父类
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 给父类添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

//实例化父类
var person = new Person('zhl',30);
//调用父类方法
//person.sayName();  // zhl

// 声明子类
function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
}
//拷贝继承
extends2(Worker.prototype,Person.prototype);
//貌似这样也可以啊:
//Object.setPrototypeOf(Worker.prototype, Person.prototype);
//给子类添加方法 Worker.prototype.sayWork = function(){ console.log(this.work); } //拷贝继承核心方法 function extends2(child,parent){ for(var attr in parent){ if(parent.hasOwnProperty(attr)){ child[attr] = parent[attr]; } } } //实例化一个子类 var worker = new Worker('vsmart',32,'itcoder'); //调用子类方法 worker.sayName(); // vsmart worker.sayWork(); // itcoder console.log(worker.flag) //false //子类自己的属性 console.log(Worker.prototype.flag) //undefined 子类原型上没有查找到 console.log(worker.constructor) // /*function Worker(name,age,work){ Person.apply(this,arguments); this.work = work; this.flag = false; }*/

 二,ES5中的继承:

  

//声明父类
function Person(name,age){   
    this.name = name;
    this.age = age;
    this.flag = true;
}
// 给父类添加方法
Person.prototype.sayName = function(){
    console.log(this.name);
}

// 声明子类
function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
}
//继承
Worker.prototype = Object.create(Person.prototype,{
    hobby:{
        value:'play',
        enumerable:true
    }
});
//改变constructor指向
Worker.prototype.constructor = Worker;

//给子类添加方法
Worker.prototype.sayWork = function(){
    console.log(this.work);
}

//实例化一个子类
var worker = new Worker('vsmart',32,'itcoder');
//调用子类方法
worker.sayName();  // vsmart
worker.sayWork(); // itcoder
console.log(worker.hobby) //play

console.log(worker.constructor)   //
/*function Worker(name,age,work){
    Person.apply(this,arguments);
    this.work = work;
    this.flag = false;
}*/

 三,ES6中的继承

  

class Person{
    //父类构造函数
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    //父类方法
    sayName(){
        console.log(this.name);
    }
}

class Worker extends Person{
    //子类构造函数
    constructor(name,age,work){
        //调用父类构造函数
        super(name,age);
        //自身独有的属性
        this.work = work;
    }
    //自身独有的方法
    sayWork(){
        console.log(this.work);
    }    
}
let person = new Person('zhl',30);
person.sayName(); //zhl
//实例化一个子类
let worker = new Worker('vsmart',32,'itcoder');
worker.sayName(); //vsmart
worker.sayWork(); //itcoder

console.log(worker.constructor)// 实例构造函数constructor指向
// class Worker extends Person{
//     constructor(name,age,work){
//         super(name,age);
//         this.work = work;
//     }
//     sayWork(){
//         console.log(this.work);
//     }    
// }
原文地址:https://www.cnblogs.com/vsmart/p/7595869.html