面向对象(OOP:Object Oriented Programming)

196 阅读5分钟

面向对象和面向过程编程

     一、面向过程:注重解决问题的步骤,分析问题需要的每一步,实现函数依次调用
     二、面向对象:是一种程序设计思想。将数据和处理数据的程序封装到对象
         将事物抽象成对象,研究每个对象的特征和行为。最后研究对象之间的关系,最终把事物的过程表示清楚。不管是通过面向对象过程还是面向对象,最终达到结果的目的是一样的。
     三、面向对象的特性:抽象、继承、封装、多态
     优点:提高代码的复用性及可维护性;

面向对象和面向过程演变

    小明去餐厅吃饭
        面向过程:小明走去餐厅看菜单点餐吃饭
        面向对象:
            1、小明(走、看、点餐、吃);
            2、餐厅(菜单)
        研究对象间的关系:小明.走餐厅 小明.看菜单 小明.点餐 小明.吃

类和对象概念

    对象:具体的某个事物;(如:小明、哈士奇)
    类:一类事务的抽象(类就是把所有对象共有的属性抽离出来);(如:人类、狗类)

对象创建

    1、字面量方式
        let obj = {name:"小明"};
    2、构造函数
        let obj = new Object();
        obj.name = "小明";
    3、Object.create() //对象创建完存在_proto_

工厂模式

    特点:工厂模式提高代码的复用性。
    
    function Person(name,hobby){
        let obj = {}; //添加原料
        obj.name = name;
        obj.hobby = function(){
            console.log(hobby);
        }; //加工原料
        return obj; //出厂
    }
    let zhangsan = Person('张三','喜欢足球');
    let lisi = Person('李四','喜欢篮球');

new运算符

    new运算符特点:
        1new执行函数; 
        2、自动创建空对象; 
        3this绑定到空对象;
        4、隐式返还this
    通过new来改造工厂模式,使创建对象更加便捷
    
    function Person(name,hobby){
        this.name = name;
        this.hobby = function(){
            console.log(hobby)
        }
    }
    let zhangsan = new Person('张三','喜欢足球')

构造函数

    特点:
        1、构造函数要通过new来调用,this指向实例化对象(属性与方法都属于实例化对象);
        2、构造函数首字母大写;
    
    静态成员
        静态属性和方法(属于类本身)。当我们需要统计所有实例化对象的次数时,我们选择是类的属性,而不是实例化对象(this)的属性。
        
        function Person(name){
            this.name = name;
            this.hobby = function(){
                console.log("喜欢篮球");
            }
        }
        Person.num = 0;
        let zhangsan = new Person("张三");
        Person.num++;
        let lisi = new Person("李四");
        Person.num++;
        console.log(Person.num) //2
        
    构造函数性能
        构造函数每创建一个对象,就会在内存地址中开辟一个空间。变得更容易消耗内存,也会消
    耗性能。
        解决:公共空间存放公共方法,公共方法是不需要重新开辟空间。

原型prototype

微信图片_20210325142937.png

    特点:
        1、通过new实例化出来的对象其属性和行为来自两个部分,一部分来自构造函数,另一部分来自原型。
        2、当声明一个函数的时候,同时也声明了一个原型。
        3、原型本身是一个对象。
        4、对象属性方法查找规则;
        
    function Person(name){
        this.name = name;
    }
    公共空间原型
    Person.prototype.hobby = function(){
        console.log("喜欢篮球");
    }
    let zhangsan = new Person("张三");
    let lisi = new Person("李四");
    
    原型关系
    zhangsan._proto_ === Person.prototype;//true
    
    原型的固有属性constructor。
        constructor主要是实例化对象通过哪个构造函数进行实例的,实例化对象的指向问题。也可以通过constructor来判断类型。
            let str = "abc"; str.constructor === String;//true
    Person.prototype.constructor === Person;//true
    zhangsan.constructor === Person;//true
    
    
    以下情况会覆盖Person.prototype中的constructor属性,需要重新指向。
    Person.prototype = {
        constructor:Person,
        hobby:function(){
            console.log("hobby")
        }
    }

原型构造函数及对象关系

微信图片_20210325143418.png 工厂模式对比构造函数

1、没有解决对象识别的问题。即创建的所有实例都是Object类型。(不清楚是哪个对象的实例)。
2、没有原型,占用内存

原型链

    对象之间的继承关系,在javascript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,成为原型链;
    1、当访问一个对象的属性或方法是,会先在对象自身上查找属性或方法是否存在,如果存在就使用自身的属性或方法。如果不存在就去创建对象的构造函数的原型对象中查找,一次类推,直到找到为止。如果到顶层对象中还找不到,则返回undefined2、原型链最顶层为Object构造函数的prototype原型对象,给Object.ptototype添加属性或方法可以,除nullundefined之外的所有数据类型对象使用。

继承

    继承:子类继承父类所有属性和行为,父类不受影响。
    原型链继承
        优点:父类方法可以复用
        缺点:1、父类所有引用属性会被子类共享,更改子类引用属性,其他子类也会受影响
             2、子类不能向父类(超类)传参
    构造函数继承
        优点:1、父类引用属性不会被子类共享
              2、子类可以向父类传参
        缺点:子类实例不能再访问父类原型上的方法
    组合继承
        优点:1、父类原型上的方法可以复用
             2、子类可以向父类传参
             3、父类构造函数的引用属性不会被共享
        缺点:
            调用了凉菜父类构造函数,消耗内存。一、在创建子类原型。二、子类型构造函数内部调用
    寄生式组合继承
        var Link = function(){};
        Link.prototype = Parent.prototype;
        Child.prototype = new Link();
        优点:1、只调用一次父类构造函数....