JavaScript面向对象

面向对象的概念:

- 两种编程思路: 函数式(过程式)、面向对象(OOP)
- 类 : 具有相同的属性和方法的一类对象的抽象
- 实例 :某一类当中的一个对象
- 对象: 具有属性和方法的具体的事物
 
面向对象的三大特点:
  1. 封装
  2. 继承
  3. 多态

继承的种种:

  • 原型链继承——把子类的原型(prototype)设置成父类的一个实例,效果就是把父类的私有和共有变成子类的共有
      ```
         /* 父类(基类) */
        function Girl(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.hair = "长头发";
        }
        Girl.prototype.chat = function () {
            console.log('hello world');
        }


        /* 子类(派生类) */
        function BeautifulGirl() {

        }
        // 把子类的原型设置为父类的一个实例
        BeautifulGirl.prototype = new Girl();

        var bg1 = new BeautifulGirl();
        console.log(bg1.hair);
        bg1.chat();
        var bg2 = new BeautifulGirl();
        console.log(bg2.hair);

      ```
  • 冒充对象继承——在子类的构造函数里边,把父类的构造函数当做普通函数执行,并且用call方法把里面的this指向改成子类的实例,效果是把父类的私有变成子类的私有
        ```
            /* 父类(基类) */
        function Girl(name, age, sex, hair) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.hair = hair;
        }
        Girl.prototype.chat = function () {
            console.log('hello world');
        }


        /* 子类(派生类) */
        function BeautifulGirl(name, age, sex, hair, longleg) {
            Girl.call(this, name, age, sex, hair); /* 冒充对象继承 */
            this.longleg = longleg;
        }
    

        var bg1 = new BeautifulGirl('真真', 18, '女', '大波浪', '大长腿');
        console.log(bg1);
        ```
  • 混合继承——原型链+冒充对象继承:父类的私有变成子类的私有,父类的公有变成子类的公有
        ```
            /* 父类(基类) */
        function Girl(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.hair = "长头发";
            this.ary = [1, 2, 3];
        }
        Girl.prototype.chat = function () {
            console.log('hello world');
        }


        /* 子类(派生类) */
        function BeautifulGirl() {

        }

        BeautifulGirl.prototype = new Girl();

        var bg1 = new BeautifulGirl();
        console.log(bg1.hair);
        bg1.ary[1] = 5;
        bg1.chat();
        var bg2 = new BeautifulGirl();
        console.log(bg2.hair);
        console.log(bg2.ary);
        ```
面向对象的创建:
  • 普通模式——每次创建对象都要设置一遍属性,属性相同时,代码冗余;
    ```
          var girl1 = {
            name: '如花',
            age: 18,
            sex: '女'
        ; 
        var girl3 = new Object();
        girl3.name = '春花';
        girl3.age = 19;
        girl3.sex = '女';

    ```
  • 工厂模式——把创建对象和返回对象的功能封装在函数中,减少代码冗余,没有类的概念;
    ```
         function girl(name, age, sex) {
            var obj = new Object();  /* 创建对象 */
            obj.name = name;
            obj.age = age;
            obj.sex = sex;
            return obj; /* 返回对象 */
        }

        var g1 = girl('如花', 18, '女');
        console.log(g1);

        var g2 = girl('似玉', 18, '女');
        console.log(g2);

        console.log(g1 instanceof girl); //false
    ```
  • 构造函数模式——有类的概念,创建出来的实例是属于同一类,使用 instanceof 运算符可以检测出来,所有的属性和方法都是实例私有的;
        - 1)-构造函数函数名首字母大写(规律)
        - 2)-用new 方式执行,new操作符会自动创建并返回对象,这个对象称之为这个类的实例
        - 3)-构造函数里面的this指向当前实例

    ```
        function Girl(name, age, sex) {
            //自动创建对象
            this.name = name;
            this.age = age;
            this.sex = sex;
            //自动返回对象
        }

        var g1 = new Girl('如花', 18, '女');
        var g2 = new Girl('似玉', 18, '女');

       // Girl('如花', 18, '女'); //如果用普通函数方式执行,里面this指向window
       // console.log(window); 
    ```
  • 原型
        - 所有对象天生自带一个属性 `__proto__`, 指向的是其构造函数的原型
        - 所有的函数天生自带一个属性 `prototype`(原型)
  • 原型+构造函数模式——即可以实现私有属性,也可以实现共有方法
        ```
             function Girl(name, age, sex, str) {
                //自动创建对象
                this.name = name;
                this.age = age;
                this.sex = sex;
                this.str = str;
                //自动返回对象
            }

            Girl.prototype.chat = function () {
                // 公有方法里面的this指向当前调用它的实例  
                console.log(this.str + 'hahaha');
            }
            var g1 = new Girl('如花', 18, '女', 'hello world');
            g1.chat();

        ```
  • 动态混合模式——把共有方法放在构造函数里边
        ```
            /* 动态混合模式 */
            function Girl(name, age, str) {
                this.name = name;
                this.age = age;
                this.str = str;
                if (typeof chat != 'function') { //如果不存在chat方法,就添加
                    Girl.prototype.chat = function () {
                        console.log(this.str);
                    }
                }
            }
            var g1 = new Girl('小红', 18, 'hello world');
        ```
 
this的指向:
  • 在普通函数中,没有对象调用,this指向window;
  • 在对象方法中,this指向调用它的对象;
  • 在事件处理函数中,this指向触发事件的元素;
  • 在构造函数中,this指向当前实例;

call和apply方法可以改变this的指向——使用方法参考:

         var obj = {
            a: 10,
            b: 20
        }
        function fn(c, d) {
            console.log(this.a + this.b + c + d);
        }
        //fn.call(obj, 30, 40);

        fn.apply(obj, [30, 40]);  //apply的第二个参数是一个数组
        fn.apply(null, [30, 40]); // 第一个参数传null,指向window

     ```

call()方法和apply()方法用法总结 - 菲比月 - 博客园 https://www.cnblogs.com/phoebeyue/p/9216514.html

原文地址:https://www.cnblogs.com/musong-out/p/11567818.html