面向对象

87 阅读4分钟

面向对象的批量生产

  • 工厂函数
       // 3. 工厂函数
        function createObj (name, age) {
            // 1. 手动创建一个对象
            const obj = {}

            // 2. 手动向对象内部添加属性
            obj.name = name
            obj.age = age

            // 3. 手动返回一个对象
            return obj
        }


        const o1 = createObj('QF001', 18)
        const o2 = createObj('QF002', 28)
        const o3 = createObj('QF003', 38)
        console.log(o1)
        console.log(o2)
        console.log(o3)
  • 自定义构造函数
        // 4. 自定义构造函数
        function createObj () {
            // 1. 自动创建出来一个对象

            // 2. 手动向对象添加属性

            // 3. 自动返回一个对象
        }

        const o1 = new createObj()  // 构造函数调用方式
        const o2 = createObj()     // 普通函数调用方式

        console.log(o1)
        console.log(o2)

自定义构造函数的书写

    1. 一定是和 new 关键字 连用
    • 如果没有和 new 连用, 那么他就是一个普通函数
    1. 当一个函数和 new 关键字连用的时候, 这个函数就被称为自定义构造函数, 这个函数内的 this 指向, 指向返回出来对象
    1. 构造函数不能使用给箭头函数
    • 因为箭头函数内部没有 this
    1. 构造函数内部不需要 return
    • return(返回) 了基本数据类型, 写了和没写一样
    • return(返回) 了引用数据类型, 写了构造函数就没用了
    1. 书写构造函数时, 首字母建议大写
    • 目的: 仅仅是为了和普通函数区分
    1. 我们构造函数 通过 new 关键字 创建出来的 对象, 叫做 实例化对象, 本质上还是一个对象, 只不过名字上叫做实例化对象(实例对象)
    • 我们把 构造函数通过 new 关键字 创建对象 的过程 叫做 实例化
       function createObj(num1, num2) {
            // 此时 this === 将来被返回出去的对象
            this.a = num1;
            this.b = num2;

            // return '我是 一个 普通字符串';   // 基本数据类型, 写了和没写一样
            // return [1, 2, 3, 4, 5];  // 引用数据类型, 写了构造函数就没用了
        }
        const o1 = new createObj(1, 2)
        const o2 = new createObj(10, 20)
        console.log(o1);
        console.log(o2);

        function Person() {
            this.name = 'QF001'
        }
        const p1 = new Person();

        /**
         *  const p1 = new Person()
         * 
         *      new Person()        此时这个过程叫做 实例化, Person函数因为和new关键字连用, 我们叫做自定义构造函数
         * 
         *      此时 常量 p1    我们叫做 实例化对象(实例对象)
        */

构造函数不合理的地方

        function Person (name, age) {
            this.name = name
            this.age = age
            this.fn = function () {
                console.log('AAAAAA')
            }
         }
       /*  
           这样写 实际功能也能完成, 但是多次创建对象时
           会多次创建 功能代码完全相同一个函数
           这对内存空间是一种浪费
       */
 function fn() {
            console.log('AAAAAA');
        }
        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.fn = fn;
            /**
             *  这样写 实际功能也能完成, 并且在多次创建的时候
             * 
             *  每次给 this.fn 赋值时, 都会去找到 fn 函数
             * 
             *  然后多个对象的 this.fn 的引用地址 都是一个
            */
        }

        /**
         *  通过 new 关键字 实例化 一个对象, 叫做 p1
         * 
         *  函数内部执行时:
         *      1. 将参数 name 赋值给 this.name
         *      2. 将参数 age 赋值给 this.age
         *      3. 创建一个函数(XF001)  赋值给 this.fn
        */
        const p1 = new Person('QF001', 18);


        /**
         * 通过 new 关键字 实例化一个对象, 叫做 p2
         *  
         *  函数内部执行时:
         *      1. 将参数 name 赋值给 this.name
         *      2. 将参数 age 赋值给  this.age
         *      3. 创建一个函数(XF002) 赋值给 this.fn
        */
        const p2 = new Person('QF002', 19);
        // console.log(p1);
        // console.log(p2);

        p1.fn();
        p2.fn();

        console.log(p1.fn == p2.fn);

原型

认识原型

    1. 每一个函数都有一个 原型(是一个空间,或者是一个对象, 内部能存储一些东西)
    • 构造函数, 本质上也是一个函数, 所以他也有这个原型
    • 原型内部都有一个 constructor ,这个属性表明当前这个原型, 是那个函数的
    • 函数访问原型; 函数.prototype
    1. 每一个对象都有一个 proto(两个下划线), 可以去访问到自己构造函数的原型
    • 实例化对象, 本质上也是一个函数, 所以他可以访问到自己构造函数的原型
    • 对象访问原型: 对象.proto
    • 对象的访问规则, 现在当前作用域(对象内部)查找, 找到就使用
    • 如果没找到, 则会顺着 proto 向上查找
    • 构造函数函数体内, 通常写属性
    • 构造函数的原型内, 通常写方法(函数)
    • 构造函数的原型内部添加方法, 并不是为了给构造函数使用
    • 通常是为了给实例化对象使用
        function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.a = '我是后续通过 JS 代码添加到函数的原型内部的属性'
        Person.prototype.sayHi = () => {
            console.log('你好');
        }


        // console.log(Person.prototype);   // 打印函数 Person 的原型


        const p1 = new Person('QF001', 18);
        const p2 = new Person('QF002', 28);
        
        // p1.sayHi();
        // console.log(p1.__proto__);
        // console.log(p1.a);

        // console.log(p1.__proto__ === Person.prototype);   // 打印对象的构造函数的原型
        
        console.log(p1.sayHi);
        console.log(p2.sayHi); 
        console.log(p1.sayHi == p2.sayHi);  // true

ES6 class类的语法

  • ES5 构造函数
      1. 函数体和原型, 是需要分开写
      1. 构造函数如果不和 new 一起连用, 不会报错
  • ES6 类的语法: class 类名 {xxxxx}
        class Stu {
            constructor(name) {
                // 这个位置和构造函数的 函数一样
                this.name = name
            }

            // 这个位置开始, 全都是原型
        }
        const s1 = new Stu('QF001')
        console.log(s1)