原型

  1. 实例化出来的对象继承构造函数的原型。
  2. 所有这个构造函数构造出来的对象,都继承于他的原型。 ```javascript function Person() { }

//给Person原型上定义一个name赋值为Lucy Person.prototype.name = ‘Lucy’;

//实例化Person var p = new Person(); console.log(p);

  1. <a name="uaom5"></a>
  2. ## 继承
  3. 1. 实例化对象继承了原型链上的**所有**属性。
  4. 1. 但是实例化对象**并没有继承自己本身含有的属性**。
  5. ```javascript
  6. Professor.prototype = {
  7. name: 'Mr Zhang',
  8. tSkill: 'JAVA'
  9. }
  10. function Professor() {
  11. }
  12. var professor = new Professor();
  13. /**
  14. * professor:{
  15. * __proto__:{
  16. * name:'Mr Zhang',
  17. * tSkill:'JAVA'
  18. * }
  19. * }
  20. */
  21. function Teacher() {
  22. this.name = 'Mr Li';
  23. this.mSkill = 'JS/JQ';
  24. }
  25. //将Professor的实例化对象赋值给Teacher当原型。
  26. Teacher.prototype = professor;
  27. //实例化Teacher
  28. var teacher = new Teacher();
  29. console.log(teacher)
  30. //将Teacher的实例化对象赋值给Student当原型。
  31. Student.prototype = teacher;
  32. function Student() {
  33. this.name = 'xiao wang';
  34. this.pSkill = 'HTML/CSS';
  35. }
  36. // 实例化student
  37. var student = new Student();
  38. //xiao wang 如果自身有这个属性。就不会往原型链上去找属性。
  39. console.log(student.name);

apply,call

  1. call,apply都是通过改变this指向的、来借用别人的属性和方法。并不是继承。 ```javascript Teacher.prototype.wife = ‘Mrs Liu’;

function Teacher(name,mSkill) { this.name = name; this.mSkill = mSkill; }

function Student(name,mSkill,age,major) { Teacher.apply(this, [name, mSkill]);//通过改变this指向来借用Teacher的属性和方法。 this.age = age; this.major = major; }

//实例化student var student = new Student(‘Axi’, ‘HTML’, 16, ‘Computer’); console.log(student);//apply,call的方式并没有让 student 继承到Teacher的prototype 这种方式构造的student无法获取到teacher原型上的属性。

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12831495/1616640028641-c8cb94ba-ea10-4a7f-ad55-dcb023732190.png#align=left&display=inline&height=291&margin=%5Bobject%20Object%5D&name=image.png&originHeight=291&originWidth=574&size=18533&status=done&style=none&width=574)
  2. - Student.prototype = Teacher.prototype 这种方式 student 继承了teacher 的原型。并不会继承teacher的属性
  3. ```javascript
  4. function Teacher() {
  5. this.name = 'Mr Wang';
  6. this.mSkill = 'JS';
  7. }
  8. //将Teacher的原型重新赋值。
  9. Teacher.prototype = {
  10. pSkill: 'JQ'
  11. }
  12. //实例化一个teacher
  13. var teacher = new Teacher();
  14. //将Student的原型赋值为Teacher.prototype。
  15. //这种方式 让student 继承了teacher 的原型上的方法和属性。但是并不会继承teacher的属性(name,mSkill)
  16. Student.prototype = Teacher.prototype;
  17. //学生构造函数
  18. function Student() {
  19. //构造函数隐式申明了一个this;并且隐式返回了一个this;
  20. this.name = 'Mr Li';
  21. }
  22. var student = new Student();
  23. console.log(student.name);//undefined
  24. console.log(student.mSkill);//undefined
  25. console.log(student.pSkill);//JQ;
  26. //添加学生构造函数上的属性
  27. Student.prototype.age = 18;
  28. //老师的构造函数原型上也多了一个age属性。说明他俩prototype指向一个对象。
  29. console.log(Teacher.prototype.age)

image.png
image.png

圣杯模式

方案:构建一个新的构造函数,这个构造函数去继承Origin的原型。而Target则去接收新的构造函数实例化的对象。这个时候Target的原型和Origin的原型就不是同一个对象了。而Target可以继承Origin的属性和方法。

  1. // 声明一个构造函数Teacher。
  2. function Teacher() { }//父类
  3. // 往Teacher的原型上添加一个age属性,并且赋值为19
  4. Teacher.prototype.age = 19;
  5. // 申明一个构造函数Student
  6. function Student() { }//子类
  7. // 将缓冲类的Buffer的原型赋值为Teacher的原型。
  8. Buffer.prototype = Teacher.prototype;
  9. function Buffer() { }//缓冲类
  10. //创建一个buffer实例。
  11. var buffer = new Buffer();//缓冲类实例
  12. //将这个实例赋值给Student的原型。
  13. Student.prototype = buffer;
  14. // 实例化Teacher
  15. var teacher = new Teacher();
  16. // 实例化student
  17. var student = new Student();
  18. // 往Student原型上添加sex 相当于给buffer添加sex属性。
  19. Student.prototype.sex = 'male';
  20. // 往Teacher原型上添加major 相当于给Buffer.prototype添加sex属性。
  21. Teacher.prototype.major = 'JAVA';
  22. console.log(student);
  23. console.log(teacher);
  24. //这个操作就不会造成修改一个构造函数原型上的属性。另外一个构造函数不会因此改变。

圣杯模式的企业级写法

  1. Teacher.prototype.name = 'Mr Wang';
  2. function Teacher() {}
  3. function Student() { }
  4. inherit(Student, Teacher);
  5. //企业级写法
  6. function inherit(Target,Origin) {
  7. function Buffer() { }//缓冲区
  8. Buffer.prototype = Origin.prototype;
  9. Target.prototype = new Buffer();//Buffer实例化赋值给目标源的prototype
  10. Target.prototype.constructor = Target;//还原构造器。函数原型上的构造器一般都指向本身。
  11. Target.prototype.super_class = Origin;//记录超类。在目标函数上记录继承源;
  12. }

构造函数形成的闭包

  1. function Compute() {
  2. var num = 10;
  3. this.add = function () {
  4. num++;
  5. console.log(num);
  6. }
  7. this.minus = function () {
  8. num--;
  9. console.log(num);
  10. }
  11. // 构造函数被实例化的时候隐式返回了一个this。这个this中包含了num,add,minus属性或方法。
  12. // 这个构造函数被执行的时, this.add,this.minus被定义。此时this.add,this.minus创建了自己的作用域和作用域链,作用域链的第0位存的是Compute的AO,第二位是GO。
  13. // 构造函数被实例化时 隐式返回了this。this中的add 和minus 都被返回出去了。所以形成了闭包。
  14. }
  15. var cp = new Compute();//实例化这个函数的时候相当于这个函数执行了一遍
  16. cp.add();//11//
  17. cp.add();//12
  18. cp.add();//13