一、原型和原型链总结

  • 原型是构造函数身上的一个属性,构造函数实例化以后就可以继承原型上的公有属性和方法
  • 原型是定义构造函数所构造出实例对象的公共祖先
  • 所有被该构造函数构造出的实例对象都会继承原型上的属性和方法
  • 原型上有一个constructor属性,它指向的是当前这个构造器,也就是构造函数本身
  • 原型的最顶端是Object.prototype
  • 原型其实也是一个对象,原型的原型一定是有Object构造出来的

    1. // 原型和原型链总结
    2. // 原型是构造函数身上的一个属性,构造函数实例化以后可以继承原型上的属性和方法
    3. // 原型是定义构造函数所构造出每一个实例对象的公共祖先
    4. // 所有被该构造函数所构造出的实例化对象都会继承原型上的属性和方法
    5. // 原型也是对象,原型的原型一定是由Object所构造出来的
    6. // 原型的最顶端是Object.prototype
    7. // 构造函数原型上有一个属性,constructor,指向的是构造器,也就是当前这个构造函数本身
    8. function Person(){}
    9. Person.prototype.name = 'Lucy';
    10. var p = new Person();
    11. console.log(p);

    二、几种对象继承的方式

    2.1、原型链继承

  • 缺点:会继承祖先身上的的所有属性和方法,同时也会继承祖先原型链上的所有属性和方法

    1. // 对象的几种继承方式
    2. // 原型链继承:缺点就是会继承祖先身上的所有的属性和方法,同时也会继承祖先原型链上所有的属性和方法
    3. Professor.prototype = {
    4. name: '张教授',
    5. tSkill: 'JAVA'
    6. }
    7. function Professor(){}
    8. var professor = new Professor();
    9. Teacher.prototype = professor;
    10. function Teacher(){
    11. this.name = '王老师';
    12. this.mSkill = 'JS/JQ';
    13. }
    14. var teacher = new Teacher();
    15. Student.prototype = teacher;
    16. function Student(){
    17. this.name = '李同学';
    18. this.pSkill = 'HTML/CSS';
    19. }
    20. var student = new Student();
    21. console.log(student);

    image.png

    2.2、call和apply继承

  • 缺点:call和apply继承,严格意义上来说只是通过改变this指向来借用方法或者是属性;它的缺点是无法继承原型上的属性或者是方法

  • call和apply两者都可以改变其this指向
  • call传递参数是一项一项传递的
  • apply传递参数是以数组的形式传递的

    1. // call和apply继承
    2. // call和apply继承,严格意义上来说只是通过改变其this指向,来借用属性或者方法;它不能继承原型上的属性或者是方法
    3. Teacher.prototype.wife = '李女士';
    4. function Teacher(name, mSkill){
    5. this.name = name;
    6. this.mSkill = mSkill;
    7. }
    8. function Student(name, mSkill, age, major){
    9. Teacher.apply(this, [name, mSkill]);
    10. this.age = age;
    11. this.major = major;
    12. }
    13. var student = new Student('王先生', 'JS/JQ', 18, 'computer');
    14. console.log(student);

    image.png

    2.3、公共原型的方法

  • 缺点:只要其中一个原型更改了属性,那么被关联的原型上的属性就会受到影响

    1. // 公共原型继承法
    2. // 只要其中一个原型更改了属性,被关联的原型上的属性就会受到影响
    3. function Teacher(){
    4. this.name = '王老师';
    5. this.tSkill = 'JAVA';
    6. }
    7. Teacher.prototype = {
    8. pSkill: 'JS/JQ'
    9. }
    10. var teacher = new Teacher();
    11. console.log(teacher);
    12. function Student(){
    13. this.name = '李同学';
    14. }
    15. Student.prototype = Teacher.prototype;
    16. Student.prototype.age = 20;
    17. var student = new Student();
    18. console.log(student);
    19. console.log(teacher);
    20. console.log(Teacher.prototype);

    image.png

    2.4、圣杯模式解决继承所产生的问题「企业级解决方案」

    原理:定义一个中间件「空的构造函数」;让中间件这个构造函数的原型等于需要被继承的这个构造函数的原型;然后实例化这个中间件对象,最后让需要继承的这个构造函数的原型等于被实例出来的这个中间件的对象

image.png

  1. // 圣杯模式继承原型
  2. function Teacher(){
  3. this.name = '王老师';
  4. this.tSkill = 'JAVA';
  5. }
  6. Teacher.prototype = {
  7. pSkill: 'JS/JQ'
  8. }
  9. var teacher = new Teacher();
  10. console.log(teacher);
  11. function Student(){
  12. this.name = '李同学';
  13. }
  14. // 定义中空的间件
  15. function Buffer(){}
  16. // 公共原型一定要在实例化对象之前
  17. Buffer.prototype = Teacher.prototype;
  18. var buffer = new Buffer();
  19. Student.prototype = buffer;
  20. Student.prototype.age = 22;
  21. var student = new Student();
  22. console.log(student.pSkill);
  23. console.log(student);

2.4.1、圣杯模式初级封装

  1. // 圣杯模式初级封装
  2. Teacher.prototype.name = '颜老师';
  3. function Teacher(){}
  4. function Student(){}
  5. inherit(Student, Teacher);
  6. // 这部分每次都需要使用,每次写代码就会过于冗余;不利用后期维护
  7. // function Buffer(){}
  8. // Buffer.prototype = Teacher.prototype;
  9. // var buffer = new Buffer();
  10. // Student.prototype = buffer;
  11. function inherit(Target, Origin){
  12. function Buffer(){}
  13. Buffer.prototype = Origin.prototype;
  14. Target.prototype = new Buffer();
  15. // 还原构造器指向
  16. Target.prototype.constructor = Target;
  17. // 定义原始的继承类
  18. Target.prototype.supper_class = Origin;
  19. }
  20. var teacher = new Teacher();
  21. var student = new Student();
  22. console.log(student);
  23. console.log(teacher);
  24. console.log(student.name);

image.png

2.4.2、复习闭包

  1. // 复习闭包
  2. // 普通闭包
  3. function test(){
  4. var num = 1;
  5. function add(){
  6. num++;
  7. console.log(num);
  8. }
  9. return add;
  10. }
  11. var add = test();
  12. add();
  13. add();
  14. add();
  15. // 普通闭包
  16. function test(){
  17. var num = 1;
  18. var compute = {
  19. add: function(){
  20. num++;
  21. console.log(num);
  22. },
  23. minus: function(){
  24. num--;
  25. console.log(num);
  26. }
  27. }
  28. return compute;
  29. }
  30. var compute = test();
  31. compute.add();
  32. compute.minus();
  33. // 构造函数也能形成闭包
  34. function Compute(){
  35. // 在实例化对象的时候系统隐式创建this对象
  36. // var this = {
  37. // add: function(){...}
  38. // minus: function(){...}
  39. // }
  40. var num = 0;
  41. this.add = function(){
  42. num++;
  43. console.log(num);
  44. }
  45. this.minus = function(){
  46. num--;
  47. console.log(num);
  48. }
  49. // 系统会隐式返回this
  50. // return this;
  51. }
  52. var compute = new Compute();
  53. compute.add();
  54. compute.minus();

2.4.3、圣杯模式进阶封装

  1. // 需要在全局定义变量,并且需要手动去执行所封装的函数
  2. var inherit = initInherit();
  3. Teacher.prototype.name = '颜老师';
  4. function Teacher(){}
  5. function Student(){}
  6. inherit(Student, Teacher);
  7. var teacher = new Teacher();
  8. var student = new Student();
  9. console.log(student);
  10. console.log(teacher);
  11. console.log(student.name);
  12. // 圣杯模式终极封装
  13. function initInherit(){
  14. var Buffer = function(){}
  15. function inherit(Target, Origin){
  16. Buffer.prototype = Origin.prototype;
  17. Target.prototype = new Buffer();
  18. // 还原构造器
  19. Target.prototype.constructor = Target;
  20. Target.prototype.supper_class = Origin;
  21. }
  22. return inherit;
  23. }

2.4.4、圣杯模式终极封装

  1. // 圣杯模式终极封装
  2. // 使用模块化思想来进行封装
  3. var inherit = (function(){
  4. var Buffer = function(){}
  5. return function(Target, Origin){
  6. Buffer.prototype = Origin.prototype;
  7. Target.prototype = new Buffer();
  8. // 还原构造器
  9. Target.prototype.constructor = Target;
  10. // 定义终极继承的超类
  11. Target.prototype.supper_class = Origin;
  12. }
  13. })();
  14. Teacher.prototype.name = '颜老师';
  15. function Teacher(){}
  16. function Student(){}
  17. inherit(Student, Teacher);
  18. var teacher = new Teacher();
  19. var student = new Student();
  20. console.log(student);
  21. console.log(teacher);
  22. console.log(student.name);

三、模块化开发

3.1、按需启动

按需启动,不让它立即执行,那就交给一个全局变量让它等待执行即可

  1. // 模块化开发
  2. // 按需启动,不让它立即执行,把它交给一个全局变量让其等待执行
  3. // 页面一加载就执行
  4. window.onload = function(){
  5. init();
  6. }
  7. // 初始化函数
  8. function init(){
  9. initCompute();
  10. initFuncs();
  11. }
  12. // // 功能函数,模块化
  13. var initCompute = (function(){
  14. var a = 1,
  15. b = 2;
  16. this.add = function(){
  17. return a + b;
  18. }
  19. this.minus =function(){
  20. return a - b;
  21. }
  22. this.mul =function(){
  23. return a * b;
  24. }
  25. this.div = function(){
  26. return a / b;
  27. }
  28. return function(){
  29. add();
  30. minus();
  31. mul();
  32. div();
  33. }
  34. })();
  35. // 功能函数,模块化
  36. var initFuncs = (function(){
  37. })();
  38. // 功能函数,模块化
  39. var initFuncs = (function(){
  40. })();

3.2、插件化开发

插件化开发,页面加载的时候就需要执行

  1. // 插件化开发
  2. // 页面加载的时候就需要执行
  3. ;function(){
  4. var Slider = function(){}
  5. // function Slider(){}
  6. Slider.prototype = {
  7. }
  8. window.Slider = Slider;
  9. }();
  10. var slider = new Slider({
  11. // 传入配置
  12. });

四、作业

把三个JS文件合并成一个

1、打印一个参数值能够同时被3或者是5或者是7同时整除的数
2、打印斐波拉契数列
3、打印从0到一个数的累加值

  1. var initCompute = (function () {
  2. // 传统闭包的模式
  3. // return function (agr) {
  4. // if (agr % 2 === 0 || agr % 3 === 0 || agr % 5 === 0) {
  5. // console.log('这个数能够同时被2或者是3或者是5整除');
  6. // }else{
  7. // console.log('小主,这个数不能够同时被2或者是3或者是5整除哦!');
  8. // }
  9. // }
  10. this.compute = function (agr) {
  11. if (agr % 2 === 0 || agr % 3 === 0 || agr % 5 === 0) {
  12. console.log('这个数能够同时被2或者是3或者是5整除');
  13. } else {
  14. console.log('小主,这个数不能够同时被2或者是3或者是5整除哦!');
  15. }
  16. }
  17. return function(){
  18. compute()
  19. }
  20. })();
  21. window.onload = function () {
  22. init();
  23. }
  24. function init() {
  25. initCompute(77);
  26. }
  1. // 课时十二作业
  2. // 1、打印一个参数值能够同时被3或者是5或者是7同时整除的数
  3. // 2、打印斐波拉契数列
  4. // 3、打印从0到一个数的累加值
  5. // 使用模块化开发
  6. window.onload = function(){
  7. init();
  8. }
  9. function init(){
  10. console.log(initDiv(10));
  11. console.log(initFb(12));
  12. console.log(initAdd(100));
  13. isLeapYear();
  14. }
  15. // 打印一个参数值能够同时被3或者是5或者是7同时整除的数
  16. var initDiv = (function(){
  17. var arr = [];
  18. return function(val){
  19. for(var i = 0; i < val; i++){
  20. if(i % 3 === 0 && i % 5 === 0 || i % 7 === 0){
  21. arr.push(i);
  22. }
  23. }
  24. return arr;
  25. }
  26. })();
  27. // 打印斐波拉契数列
  28. var initFb = (function(){
  29. function fb(num){
  30. var num = num || 0;
  31. if(num < 0){
  32. return 0;
  33. }
  34. if(num <= 2){
  35. return 1;
  36. }
  37. return fb(num - 1) + fb(num - 2);
  38. }
  39. return fb;
  40. })();
  41. // 打印从0到一个数的累加值
  42. var initAdd = (function(){
  43. return function add(num){
  44. var num = num || 0;
  45. if(num === 1){
  46. return 1;
  47. }
  48. return num + add(num -1);
  49. }
  50. })();
  51. // 从window.prompt输入一个年份判断是不是闰年,用三目运算符
  52. var isLeapYear = (function(){
  53. return function(){
  54. var year = Number(window.prompt('请输入年份'));
  55. // if(year % 4 === 0 && year % 100 !== 0 || year % 400 === 0){
  56. // console.log('是闰年');
  57. // }else{
  58. // console.log('是平年');
  59. // }
  60. return year = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ? console.log('是闰年')
  61. : console.log('是平年')
  62. }
  63. })();