一、面向对象编程


1、什么是面向对象编程

面向对象是一种编程思想,经常拿来和面向过程比较

1.1 面向过程编程VS面向对象编程

1、面向过程编程:
面向过程过程的重点是动词,是分析出解决问题需要的步骤,然后后编写函数实现每个步骤,最后依次调用函数
2、面向对象编程:
面向对象关注重点但是主谓,是吧构成问题的事物拆解成各个对象,而拆解出对象的目的也不是为了实现某个步骤,二十为了描述这个事物在当前问题中的各种行为

1.2 面向对象特点

  1. 继承:就是为了实现代码的复用,从父类上继承出一些属性方法,子类也有自己的一些属性
  2. 封装:让使用对象的人不考虑内部实现,只考虑功能使用,把内部的代码保护起来,只有一些api供用户使用
  3. 多态:是不同对象作用域统一操作产生不同的效果。多态的思想实际上是吧“想做什么”和“谁去做”分开

    2、JS中的面向对象

    2.1 对象包含什么

  • 属性
  • 方法

    2.2 常用内置对象

  • Object

  • Array
  • Date
  • Function
  • RegExp

    2.3 创建对象

    1、普通方法
    通过new Object()构造函数创建对象,然后后设置属性和方法
    1. let Player = new Object()
    2. // 再添加属性和方法
    3. Player.name = 'yongzhi'
    工程模式
    1. function createObject () {
    2. const Player = new Object()
    3. Player.name = 'yongzhi'
    4. Player.run = function () {
    5. console.log(this.name + 'run')
    6. }
    7. return Player
    8. }
    2、构造函数/实例
    this添加的属性和方法总是指向当前对象,所以实例化的时候,通过this添加的属性和方法都会在内存中复制一份,这样会造成内存浪费
    缺点:会造成内存浪费
    优点:即使改变某一个对象和方法,不会影响到其他的对象
    1. function Player(name){
    2. this.name = name;
    3. this.run = function(){
    4. console.log(this.name+"run")
    5. }
    6. }
    7. const p1 = new Player("p1");
    8. const p2 = new Player("p2");
    3、原型
    通过原型继承的方法不是自身的,我们要在原型链上一层一层的查找,这样创建的好处是在内存中创建一次,实例化的对象都会指向这个prototype对象
    1. function Player (name) {
    2. this.name = name
    3. }
    4. player.prototype.run = function () {
    5. console.log(this.name + 'run')
    6. }
    7. const p1 = new Player('p1')
    8. const p2 = new Player('p2')
    4、静态属性
    是绑定在构造函数上的属性和方法,需要通过构造函数访问
    1. function Player () {
    2. if(!Player.total) {
    3. Player.total = 0
    4. }
    5. Player.total++
    6. }

    二、原型及原型链

    1、new

  1. 创建一个继承自Player.prototype的新对象
  2. 新对象的属性proto指向prototype
  3. 将this指向新建的对象
  4. 返回新对象
    1. 如果构造函数没有显式返回值,则返回this
    2. 如果构造函数有显式返回值,是基本类型,那么返回this
    3. 如果构造函数有显式返回值,是对象,则返回这个对象
  1. function objectFactory () {
  2. const obj = new Object()
  3. let Constructor = [].shift.call(arguments)
  4. obj.__proto__ = Constructor.prototype;
  5. let ret = Constructor.apply(obj,arguments);
  6. return typeof ret === 'object'?ret:obj
  7. }

2、原型链

当读取实例的属性时,如果找不到,就会查找与对象相关链的原型中的属性,如果查找不到,就是取查找原型的原型,一直找到最顶层为止yuanxing.webp.jpg

三、继承

1、原型链继承

1.1 实现

  1. function Parent() {
  2. this.name = 'parent'
  3. }
  4. Parent.prototype.getName = function () {
  5. console.log(this.name)
  6. }
  7. function Child () {}
  8. Child.prototype = new Parent()
  9. Child.prototype.constructor = Child
  10. var child = new Child()
  11. child.getName()//parent

1.2 缺点

  1. 如果有属性是引用类型的,一旦某个实例修改了这个属性,所有的实例都会受到影响
  2. 创建Child实例的时候,不能传参

2、构造函数继承

2.1实现

  1. function Parent (name,actions) {
  2. this.name = name
  3. this.actions = actions
  4. }
  5. function Child (id,name,actions) {
  6. Parent.apply(this,Array.from(arguments).splice(1))
  7. this.id = id
  8. }
  9. const child1 = new Child(1, "c1", ["eat"]);
  10. const child2 = new Child(2, "c2", ["sing", "jump", "rap"]);
  11. console.log(child1.name); // c1
  12. console.log(child2.name); // c2

2.2 缺点

  1. 属性或方法想被继承的话,只能在构造函数中定义。如果方法在构造函数中定义了,那么每次创建实例都会创建一遍方法,多占一块内存

    3、组合继承

    3.1 实现

    1. function Parent (name,actions) {
    2. this.name = name
    3. this.actions = actions
    4. }
    5. Parent.prototype.eat = function () {
    6. console.log(this.name + '-eat')
    7. }
    8. function Child (id) {
    9. Parent.apply(this,Array.from(arguments).splice(1))
    10. this.id = id
    11. }
    12. Child.prototype = new Parent()
    13. Child.prototype.constructor = Child
    14. const child1 = new Child(1, "c1", ["eat"]);
    15. const child2 = new Child(2, "c2", ["run"]);
    16. child1.eat(); // c1 - eat
    17. child2.eat(); // c2 - eat
    18. console.log(child1.eat === child2.eat); // true

    3.2 缺点

    调用了两次构造函数,重复操作
    1. Parent.apply(this,Array.from(arguments).slice(1))
    2. Child.prototype = new Parent();

    4、寄生组合继承

    4.1 实现

    ```javascript function Parent(name,action){ this.name = name; this.actions = actions; } Parent.prototype.eat = function(){ console.log(this.name+”-eat”) } function Child(id){ Parent.apply(this,Array.from(arguments).slice(1)); this.id =id; } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; const child1 = new Child(1, “c1”, [“eat”]); const child2 = new Child(2, “c2”, [“run”]);

```