• 23种设计模式:是一种编程思想

    (一)面向对象

  • 面向对象是一种程序的设计思想,与之相对的编程思想叫面向过程

  • 举个例子感受一下:比如我们想用代码描述一个这样的场景,有一只叫做XiaoA的猫,吃了一个苹果,又吃了一条鱼,然后有一只叫做xiaoB的猫,吃了一根香蕉
  1. //面向过程编程
  2. function xiaoAEatApple(){}
  3. function xiaoAEatFish(){}
  4. function xiaoBEatBanana(){}
  5. xiaoAEatApple();
  6. xiaoAEatFish();
  7. xiaoBEatBanana();
  1. //面向对象编程
  2. function Cat(name){
  3. this.name = name;
  4. }
  5. Cat.prototype.eat = function(somthing) {}
  6. var xiaoA = new Cat('xiaoA');
  7. var xiaoB = new Cat('xiaoB');
  8. xiaoA.eat('apple');
  9. xiaoA.eat('fish');
  10. xiaoB.eat('banana');
  • 面向对象的特点
    • 面向对象注重于抽象事物,而面向过程注重于叙述事物
    • JS通过函数和原型,模拟了传统面向对象编程中的类的概念,实现了面向对象的编程模式
    • 面向对象的编程思想,主要为了实现 3 件事:封装、继承、多态

封装

  1. var catA = {
  2. name: 'xiaoA',
  3. eat: function(){
  4. console.log('xiaoA eat something');
  5. }
  6. }
  7. var catB = {
  8. name: 'xiaoB',
  9. eat: function(){
  10. console.log('xiaoB eat something');
  11. }
  12. }
  13. var catC = {
  14. name: 'xiaoC',
  15. eat: function(){
  16. console.log('xiaoC eat something');
  17. }
  18. }
  19. //封装
  20. //使用工厂模式进行封装
  21. function CreateCat(name){
  22. var obj = {};
  23. obj.name = name;
  24. obj.eat = function(){
  25. console.log(name + ' eat something');
  26. }
  27. return obj;
  28. }
  29. var xiaoA = CreateCat('xiaoA');
  30. var xiaoB = CreateCat('xiaoB');
  31. var xiaoC = CreateCat('xiaoC');
  32. //使用面向对象进行封装
  33. function CreateCat(name){
  34. this.name = name;
  35. this.eat = function(){
  36. console.log(this.name + 'eat something');
  37. }
  38. }
  39. var xiaoA = new CreatCat('xiaoA');
  40. var xiaoB = new CreatCat('xiaoB');
  41. var xiaoC = new CreatCat('xiaoC');
  42. /*
  43. new 做了啥
  44. 1. 创建一个空对象
  45. 2. 把构造函数的prototype赋值给新对象的__proto__
  46. 3. 把构造函数的this,指向新对象
  47. 4. 把构造函数的代码,执行一遍
  48. 5. 把新对象返回
  49. */
  50. /*
  51. 如 var xiaoA = new CreatCat('xiaoA') -->
  52. {
  53. __proto__: CreateCat.prototype,
  54. name: 'xiaoA',
  55. eat: function() {console.log(this.name + 'eat something')},
  56. }
  57. */

继承

  1. //继承
  2. /*
  3. * new 做了哪些操作
  4. * 1.创建一个空对象
  5. * 2.将构造函数的prototype属性赋值给新对象的__proto__
  6. * 3.将构造函数的this指向新对象
  7. * 4.执行构造函数的代码
  8. * 5.将新对象返回
  9. */
  10. //在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法
  11. function CreateCat(name){
  12. this.name = name;
  13. }
  14. CreateCat.prototype.eat = function(something){
  15. console.log(this.name + ' eat ' + something);
  16. }
  17. var catA = new CreateCat('xiaoA');
  18. // catA.eat('fish');
  19. console.log(catA);
  20. console.log(CreateCat.prototype);
  21. /*
  22. CreateCat.prototype = new Object() -> {
  23. __proto__: Object,
  24. constructor: CreateCat(){...},
  25. eat: function(something){...}
  26. }
  27. catA = {
  28. __proto__: CreateCat.prototype,
  29. name: 'xiaoA'
  30. }
  31. */
  32. // 在js里规定,访问对象的属性和方法时,如果对象下没有这个属性或方法,则沿着他的__proto__一直往上找,直到尽头
  33. // 一、类式继承
  34. function A(name) {
  35. this.name = name;
  36. this.list = [1,2,3];
  37. }
  38. A.prototype.getName = function(){
  39. console.log(this.name);
  40. }
  41. function SubA(){
  42. this.subName = 'sub' + this.name;
  43. }
  44. //类式继承一波,注意这里莫得参数,导致undefined
  45. SubA.prototype = new A();
  46. var one = new SubA('one');
  47. console.log(one);
  48. console.log(SubA.prototype);
  49. /*
  50. SubA.prototype = new A() -> {
  51. __proto__: A.prototype,
  52. name: undefined,
  53. list: [1,2,3]
  54. }
  55. new SubA('one') -> {
  56. __proto__: SubA.prototype,
  57. subName: 'subundefined'
  58. }
  59. //类式继承的问题
  60. //1.这种方法不支持父构造函数带参数
  61. //2.父构造函数中的属性和方法都变成共有属性
  62. */
  63. // 二、构造函数继承
  64. function A(name) {
  65. this.name = name;
  66. this.list = [1,2,3];
  67. }
  68. A.prototype.getName = function(){
  69. console.log(this.name);
  70. }
  71. function SubA(name){
  72. //构造函数继承一波
  73. A.call(this, name);
  74. this.subName = 'sub' + this.name;
  75. }
  76. let s1 = new SubA('one');
  77. console.log(s1.name, s1.subName);
  78. console.log(s1);
  79. s1.getName(); //报错
  80. /*
  81. new SubA('one'): -> {
  82. __proto__: SubA.prototype,
  83. name: 'one',
  84. list:[1,2,3],
  85. subName: 'subone'
  86. }
  87. //构造函数的问题:不能继承父构造函数的原型方法
  88. */
  89. //三、组合式继承:类式继承+构造函数继承
  90. function A(name) {
  91. this.name = name;
  92. this.list = [1,2,3];
  93. }
  94. A.prototype.getName = function(){
  95. console.log(this.name);
  96. }
  97. function SubA(name){
  98. //关键一
  99. A.call(this, name);
  100. this.subName = 'sub' + this.name;
  101. }
  102. //关键二
  103. SubA.prototype = new A();
  104. let one = new SubA('xiaoA');
  105. console.log(one);
  106. one.getName();
  107. /*
  108. SubA.prototype = new A(): ->{
  109. name: undefined,
  110. list: [1,2,3],
  111. __proto__: {
  112. getName: fn
  113. }
  114. }
  115. new SubA("xiaoA"): -> {
  116. name: 'xiaoA',
  117. list: [1,2,3],
  118. subName: 'sub xiaoA',
  119. __proto__: {
  120. name: undefined,
  121. list: [1,2,3],
  122. __proto__: {
  123. getName: fn
  124. }
  125. }
  126. }
  127. //组合式继承的小问题
  128. //1. __proto__里面的属性没有用
  129. //2.执行了两次父构造函数
  130. */
  131. //四、寄生组合式继承
  132. function A(name) {
  133. this.name = name;
  134. this.list = [1,2,3];
  135. }
  136. A.prototype.getName = function(){
  137. console.log(this.name);
  138. }
  139. function SubA(name){
  140. //关键一
  141. A.call(this, name);
  142. this.subName = 'sub' + this.name;
  143. }
  144. //关键二:直接new太暴力了
  145. // SubA.prototype = new A();
  146. //换这个方式
  147. function inheritPrototype(subClass, superClass) {
  148. function F(){}
  149. F.prototype = superClass.prototype;
  150. subClass.prototype = new F();
  151. // subClass.prototype.constructor = subClass;
  152. }
  153. inheritPrototype(SubA, A);
  154. let one = new SubA('xiaoA');
  155. console.log(one);
  156. one.getName();
  157. /*
  158. new SubA('xiaoA') --> {
  159. __proto__: new F(),
  160. name: 'xiaoA',
  161. list: [1,2,3],
  162. subName: 'subXiaoA'
  163. }
  164. new F() --> {
  165. __proto__: superClass.prototype(A.prototype)
  166. }
  167. */

多态

  1. //多态: 表示不同对象调用相同方法。会产生不同的结果
  2. function Base(){}
  3. Base.prototype.initial = function(){
  4. this.init();
  5. }
  6. function SubA(){
  7. this.init = function(){
  8. console.log('SubA');
  9. }
  10. }
  11. function SubB(){
  12. this.init = function(){
  13. console.log('SubB');
  14. }
  15. }
  16. SubA.prototype = new Base();
  17. SubB.prototype = new Base();
  18. /*
  19. SubA.prototype = new Base() -->
  20. {
  21. __proto__: Base.prototype = { initial: function() { this.init(); // new的时候,this指向SubA } },
  22. init: function(){ console.log('SubA')}
  23. }
  24. 同理
  25. SubB.prototype = new Base() -->
  26. {
  27. __proto__: Base.prototype = { initial: function() { this.init(); // new的时候,this指向SubB } },
  28. init: function(){ console.log('SubB')}
  29. }
  30. 所以SubA和SubB调用initial会有不同的结果
  31. */
  32. var subA = new SubA();
  33. var subB = new SubB();
  34. subA.initial();
  35. subB.initial();