# 原型原型链介绍

进去搜索往下找到 10_原型&原型链


# 原型之间的关系

img

# 原型链原理

function Car() {
  age: 18

  AO = {
    var this = {
      age: 18,
      __proto__: Car.prototype = {
        name: 'Benz'
      }
    }
  }

}
Car.prototype.name = 'Benz'
var car = new Car();
console.log(car);// Benz

Go = {
  car: {
    name: 'Benz'
  }
}

# 原型链继承

(ES5)继承:当我们想使用其他函数原型上的方法时,我们就可以通过原型链继承的方式来减少一些不必要的重复代码,提高可复用性。


# 1.原型链逐步继承方式

问题:Student把Teacher不是原型的属性也继承过来了, Student在原型上添加属性, Teacher也增加属性。

Teacher.prototype.name = 'aa';
function Teacher() {
  this.a = 'a';
}
var t = new Teacher();

Student.prototype = t;
function Student() {
  this.b = 'b';
}

var s = new Student();
Student.prototype.age = '111'
console.log(t);
console.log(s);

# 2.借助call/apply方式

问题:Student无法继承Teacher原型属性, 每次构造函数都要多走一个函数,浪费资源。

Teacher.prototype.a = 'aa';
function Teacher() {
  this.a = 'a';
}
var t = new Teacher();

Student.prototype.b = 'bb';
function Student() {
  Teacher.apply(this)
  this.b = 'b';
}

var s = new Student();
console.log(t)
console.log(s);

# 3.公共原型方式

问题:现在只继承Teacher原型属性了,但Student原型更改属性,Teacher原型属性也更改。

Teacher.prototype.a = 'aa';
function Teacher() {
  this.a = 'a';
}
var t = new Teacher();

Student.prototype = Teacher.prototype;
function Student() {
  this.b = 'b';
}

var s = new Student();

Student.prototype.age = '18';
console.log(t)
console.log(s);

# 4.圣杯模式 完美实现原型继承

利用一个Buffer中转函数,通过Buffer函数的原型继承Teacher原型属性,在通过Buffer实例化对象赋值给Student原型方式,

实现了只继承Teacher原型,但又随意更改Student原型属性,这就是圣杯模式实现的方法。

Teacher.prototype.a = 'aa';
function Teacher() {
  this.a = 'a';
}
var t = new Teacher();


Buffer.prototype = Teacher.prototype;
function Buffer() {}
var buffer = new Buffer();

Student.prototype = buffer;
function Student() {
  this.b = 'b';
}

var s = new Student();

Student.prototype.age = '18';
console.log(t)
console.log(s);

# 1.圣杯模式初步封装成函数

Target目标(谁继承) Origin继承源(被继承)

function Test(Target, Origin) {
  Buffer.prototype = Origin.prototype;
  function Buffer() {}
  var buffer = new Buffer;
  Target.prototype = buffer;
}

Teacher.prototype.a = 'aa';
function Teacher() {
  this.a = 'a';
}
var t = new Teacher();

Test(Student, Teacher);

function Student() {
  this.b = 'b';
}

var s = new Student();

Student.prototype.age = '18';
console.log(t);
console.log(s);


# 2.改造一下 (YUI3) 最终的圣杯模式写法

var inherit = (function () {
  var Buffer = function () {}
  return function (Target, Origin) {
    Buffer.prototype = Origin.prototype;
    Target.prototype = new Buffer();
    Target.prototype.constructor = Target;// 构造器指向
    Target.prototype.super_class = Origin;// 继承源
  }
})();


Teacher.prototype.a = 'aa';
function Teacher() {
  this.a = 'a';
}
var t = new Teacher();

inherit(Student, Teacher);

function Student() {
  this.b = 'b';
}

var s = new Student();

Student.prototype.age = '18';
Student.prototype.hhh = 'hello';
console.log(t);
console.log(s);

# 圣杯模式图解

image

# 圣杯模式写法

var inherit = (function () {
  var Buffer = function () {}
  return function (Target, Origin) {
    Buffer.prototype = Origin.prototype;
    Target.prototype = new Buffer();
    Target.prototype.constructor = Target;
    Target.prototype.super_class = Origin;
  }
})();

# 圣杯模式案例

var inherit = (function () {
  var Buffer = function () {}
  return function (Target, Origin) {
    Buffer.prototype = Origin.prototype;
    Target.prototype = new Buffer();
    Target.prototype.constructor = Target;
    Target.prototype.super_class = Origin;
  }
})();

var initProgrammer = (function () {
  var Programmer = function () {}
  Programmer.prototype = {
    name: '程序员',
    tool: '计算机',
    work: '编写应用程序',
    diration: '10个小时',
    say: function () {
      console.log(
        '我是一名' + this.myName + this.name + ',' + 
        '我的工作是用' + this.tool + this.work + ',' + 
        '我每天工作' + this.diration + ',' + 
        '我的工作需要用到' + this.lang + '。'
      );
    }
  }

  var FrontEnd = function () {}
  var BackEnd = function () { }

  inherit(FrontEnd, Programmer);
  inherit(BackEnd, Programmer);

  FrontEnd.prototype.lang = ['HTML', 'CSS', 'JavaScript'];
  FrontEnd.prototype.myName = '前端';
  
  BackEnd.prototype.lang = ['JAVA', 'SQL', 'Node'];
  BackEnd.prototype.myName = '后端';

  return {
    FrontEnd,
    BackEnd
  }

})();

var frontEnd = new initProgrammer.FrontEnd();
var backEnd = new initProgrammer.BackEnd();

frontEnd.say();
backEnd.say();


# 总结

原型:原型prototype是function对象的一个属性,在构造函数实例化new的时候产生了this,this里面保存了__proto__这个隐式属性,__proto__里面就保存了prototype这个属性值。

原型链:实例化对象是可以沿着__proto__一层一层像上查找属性或方法的,一直到Object.prototype为止这个查找关系我们可以称之为原型链。

原型链继承:当我们想使用其他函数原型上的方法时,我们就可以通过原型链继承的方式来减少一些不必要的重复代码,提高可复用性,常用的继承方式比如说圣杯模式。

作用: 原型链可以用来做继承,当一些我们不需要经常变更的方法或属性我们都可以写在prototype上, 当我们通过实例化对象访问的时候就会继承prototype上的方法或属性, 如果这个方法或属性在构造函数中存在,那么会优先查找构造函数中的,构造函数没有才会向父级原型上查找。