javaScript 继承方法

401 阅读3分钟

回顾知识:构造函数会有一个原型对象属性(prototype),原型对象有一个属性construct指回构造函数,而实例包含一个指向原型对象的内部指针(__ proto__)。

原型链继承

概念:让原型对象等于另一个类型的实例,另一个类型的实例的原型又是指向原型对象,这样层层递进,实现了继承。

function Father(){
    this.name = "hzs";
    this.age = 22;
    this.colors = ['red', 'green', 'purple'];
}
Father.prototype.getPersonValue = function(){
    return this.name
}
function Children(){
    this.name = "yqe"
}
// 继承了父类
Children.prototype = new Father();
// 在子类增加新的属性,要放在替换原型之后去做
Children.prototype.getChildrenValue = function(){
    return this.age;
}
Children.prototype.text = "课本";
let chil = new Children();
et chilT = new Children();
console.log(chil.getChildrenValue()); // 22
chil.colors.push("black");
console.log(chil.colors); //["red", "green", "purple", "black"]
console.log(chilT.colors); //["red", "green", "purple", "black"]

缺陷:(1)引用类型值的原型共享给所有继承,值会受到它们的影响;(2)创建子类型的实例时,不能向超类型函数传递参数

借用构造函数

概念,在子类型的构造函数的内部调用超类型构造函数。

function Father(name) {
    this.colors = ['red', 'green', 'purple'];
    this.name = name;
}
// 用call方法在子类型构造函数中调用超类型的构造函数。
function Children() {
    this.name = "yqe"
    Father.call(this, 'huangzishuan');
}
console.log(chil.colors); //["red", "green", "purple", "black"]
console.log(chilT.colors); //["red", "green", "purple"]

结果:通过使用call方法,实际是在将要创建children实例的环境下调用Father构造函数,这样一来,就会在新Children对象上执行Father函数中定义的所有对象初始化代码。结果,每个Children的实例就有自己的colors属性的副本了。

缺陷:父类原型,子类访问不了

组合继承(原型链和借用构造函数结合体)

function Father() {
    this.colors = ['red', 'green', 'purple'];
}
Father.prototype.sex = "男";
Father.prototype.remove = function() {
  console.log(
}
function Children() {
    this.name = "yqe"
    Father.call(this);
}
// 继承了父类
Children.prototype = new Father();
Children.prototype.constructor = Children;
let chil = new Children();
let chilT = new Children();
chil.colors.push("black");
console.log(chil.colors);//["red", "green", "purple", "black"]
console.log(chilT.colors);//["red", "green", "purple"]
chil.remove();//"father原型的方法"

结果:组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点。实现父类引用类型不会被实例干扰,和子类可以传参给父类。

缺陷:需要调用两次父类构造函数

原型式继承

概念:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

function object(o) {
    function F(){}
    F.prototype = o;
    return new F();
}

注释:ES5新增Object.create()方法规范了原型式继承,第一个参数用作新对象原型的对象和(可选)一个为新对象定义额外属性的对象。在传入一个参数时,其跟object()方法相同。

举个栗子:

var person = {
    name: "NICK",
    friends: ["sendy", "yike"];
}
var anotherPerson = Object.create(person, {
    name: {
        value: "Grek";
    }
})
console.log(anotherPerson.name); //Grek

缺陷:包含引用类型值得属性始终都会共享相应的值

寄生式继承

概念:与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象

举个栗子:

function createAnother(original){
    var clone = object(original);//通过调用函数创建一个对象
    clone.sayHi = function() {
        console.log("hi");
    }
    return clone;
}
var person = {
    name: "nick",
    age: 15
}
var anotherPerson = createAnother(person);
another.sayHi(); //hi

缺陷:函数不可复用

寄生组合继承(原型式和寄生的结合体)

function inheritPrototype(children, father) {
  let prototype = Object(father.prototype); 
  prototype.constructor = children;
  children.prototype = prototype;
}
function Father() {
    this.colors = ['red', 'green', 'purple'];
}
Father.prototype.sex = "男";
Father.prototype.remove = function() {
  console.log(father原型的方法);
}
function Children() {
    this.name = "yqe"
    Father.call(this);
}
inheritPrototype(Children, Father);
// 继承了父类
let chil = new Children();
let chilT = new Children();
chil.colors.push("black");
console.log(chil.colors);//["red", "green", "purple", "black"]
console.log(chilT.colors);//["red", "green", "purple"]
chil.remove();//"father原型的方法"

结果:这个例子体现在只调用了一次Father构造函数,同时原型链还能保持不变。