面向对象、构造函数

168 阅读4分钟

一、面向对象:以对象作为基本单元进行编程

    OO -> Object Oriented 面向对象
    OOA -> Object Oriented Analyse 面向对象分析
    OOD -> Object Oriented Design 面向对象设计
    OOP -> Object Oriented Programming 面向对象编程
  • 类(构造函数): 是描述一组具体相同行为和特征的对象,这些对象的抽象就是类
  • 对象:类的具体实例,是包含属性和方法的集合
  • 面向对象的特征:封装、继承、多态、抽象
     封装:外界对客体内部属性的所有访问只能通过提供的用户接口实现。对象是封装的最基本单位。
     继承:继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。
     多态:多态性是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果,
          不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。
     抽象:抽象是指强调实体的本质、内在的属性,
          在系统开发中,抽象指的是在决定如何实现对象之前的对象的意义和行为
    
  • OOP的好处: 复用性、灵活性、扩展性
  • 面向对象解决的问题:
    • 创建多个对象时,需要写大量重复代码
    • 创建的多个对象无法按类型分类(无法进行类型识别)
    • 相同类型的不同对象的行为方法不能复用(重复创建)

(一)、工厂模式

缺点:

  • 无法进行类型识别
  • 重复创建方法
        function factory(name,age,sex){
            let obj = new Object()
            obj.name = name
            obj.age = age
            obj.sex = sex
            obj.say = function(){console.log('hi~')}
        }
        let res1 = factory('张三',25,'男')
        let res2 = factory('李四',20,'男')
        console.log(res1.constructor) // Object
        console.log(res2.constructor) // Object
        console.log(res1.say == res2.say) // false
    

(二)、构造函数(另类的工厂模式)

缺点:

  • 重复创建方法
        function Human(name,age,sex){
            // this -> new 出来的实例对象
            // let this = new Object()  工厂模式
            this.name = name
            this.age = age
            this.sex = sex
            this.say = function(){console.log('hi~')}
            // return this  工厂模式
    }
        let res1 = new Human('张三',25,'男')
        let res2 = new Human('李四',20,'男')
        console.log(res1.constructor) // Human
        console.log(res2.constructor) // Human
        console.log(res1.say == res2.say) // false
    

(三)、原型模式

缺点:

  • 所有的对象共享特征
        function Human(){
            Human.prototype.name = '张三'
            Human.prototype.age = '25'
            Human.prototype.sex = '男'
            Human.prototype.say = function(){console.log('hi~')}
        }
        let res1 = new Human()  
        let res2 = new Human()
        console.log(res1.name) // 张三
        console.log(res2.name) // 张三
        console.log(res1.constructor) // Human
        console.log(res2.constructor) // Human
        console.log(res1.say == res2.say) // true
    

(四)、混合模式

```
    //构造函数
    function Human(name,age,sex){
        this.name = name
        this.age = age
        this.sex = sex
    }
    //在原型对象上添加方法
    Human.prototype.say = function(){console.log('hi~')}
    let res1 = new Human('张三',25,'男')
    let res2 = new Human('李四',20,'男')
    console.log(res1.name) // 张三
    console.log(res2.name) // 李四
    console.log(res1.constructor) // Human
    console.log(res2.constructor) // Human
    console.log(res1.say == res2.say) // true
```
  • 面向对象的目标 : 对一个对象进行编程
  • 面向对象的变量与属性:在同一作用域中使用变量,不同作用域中使用属性
  • 构造函数的作用 : 提供一个对象供你编程
  • 面向对象编程就是通过构造函数进行编程

(五)、示例

   //模块化  形成独立作用域
    (function(){
        //1.创建构造函数
            function Drag(obj){
                //this -> 实例对象
                this.dom = $(obj)
                this.index = 1
                this.addEvent() //调用函数
            }
        //2.添加事件
            //在原型对象上添加属性,共享方法
            Drag.prototype.addEvent = function(){
                //this -> 实例对象
                let _this = this  //缓存this指向
                this.dom.onclick=function(){
                    //this -> 添加事件的元素(this.dom)
                    _this.index //1
                }
            }
        //3.拆分组合
            function $(obj) return document.querySelector(obj)
        //4.工厂模式
            function factory(obj){
                return new Drag(obj)  //返回实例对象
            }
        //5.对外暴露
            window.drag = factory //给window添加属性
    })()
   //调用函数
      drag('.box')

二、构造函数

(一)、运算符

  • in运算符:

    判断属性是否在整个原型链中,返回布尔值 attr in obj

        let obj={name:'张三'}
        Object.prototype.hehe = '呵呵'
        console.log('hehe' in obj) //true
        //obj.hasOwnProperty(attr) 判断obj对象自身是否包含attr属性,返回布尔值
        console.log(obj.hasOwnProperty('hehe')) //false
    
  • instanceof运算符:

    判断一个 对象 的整个原型链中是否包含某个构造函数的prototype

        let obj = {name:'张三'}
        let num = 1 //基本数据类型
        let str = new String() //对象包装
        console.log( obj instanceof Object );// true
        console.log( num instanceof Object );// false
        console.log( str instanceof Object );// true
        console.log( Object.prototype instanceof Object );// false 
    
  • new运算符

    new运算符做了哪些工作?

    • 1.创建一个空对象 : var obj = new Object()
    • 2.将obj._proto_的this指向改为Test.prototype
       obj._proto_ = Test.prototype
      
    • 3.将构造函数的内部this指向obj对象
       Test.call(obj)  //this -> 实例对象
      
    • 4.Test执行后默认返回obj对象 : return obj
    function Test(name){
        this.name=name
    }
    let res = new Test('张三') // Test {name: '张三'}

(二)、构造函数

  • 返回值 : new运算符一定返回一个object类型

    • return为基本类型 : 执行return this
    • return为引用类型 : 以return值为准
          function Test(){
              return 666
              return [1,2,3]
          }
          let res = new Test();
          console.log(res) //Test{}         
          console.log(res) //[1,2,3]
      
  • 继承 : 一个对象共享另一个对象的属性方法

    原理 : 在子类中调用父类构造函数,并改变父类中的this指向

    //父类
     function Cat(name,color){
         //this -> Cat
         this.name = name
         this.color = color
     }
     Cat.prototype.skill = function(){console.log('抓老鼠')}
     //子类
     function Dog(food,name,color){
         this.food = food
         Cat.call(this,name,color) // this -> Dog
     }
    

1.构造函数继承

    let res = new Dog('water','耶耶','white')
    res.skill() //报错
    console.log(res)//Dog {food: 'water', name: '耶耶', color: 'white'}
    /*原型链
      res -> res._proto_ -> Dog.prototype -> Dog.prototype._proto_ 
          -> Object.prototype
    */

2.原型继承 : 修改原型链

  • Dog.prototype = Cat.prototype

        Dog.prototype = Cat.prototype
        res.skill() //抓老鼠
        /*原型链
            res -> res._proto_ -> Dog.prototype -> Cat.prototype 
                -> Cat.prototype._proto_ -> Object.prototype
        */
    
  • Dog.prototype = new Cat()

        Dog.prototype = new Cat() //实例对象
        res.skill() //抓老鼠
        /*原型链
             res -> res._proto_ -> Dog.prototype -> Cat实例对象 
                 -> Cat实例对象._proto_  -> Cat.prototype
                 -> Cat.prototype._proto_  -> Object.prototype
         */
    
  • Dog.prototype = Object.create(Cat.prototype)

        Dog.prototype = Object.create( Cat.prototype ) //obj
        res.skill() //抓老鼠
        /*原型链
              res -> res._proto_ -> Dog.prototype -> obj
                  -> obj._proto_ -> Cat.prototype
                  -> Cat.prototype._proto_  -> Object.prototype
          */
    

    Object.create(obj/null)创建一个空对象,并指定该对象的原型对象

      let test = { name: '呵呵' };
      let res = Object.create(test);
      let res1 = Object.create(null);
      let res2 = {};
      console.log(res);  // {} test.prototype
      console.log(res1); // {} 无 prototype 属性
      console.log(res2); // {} Object.prototype
    

3.混合继承

    function Dog(food,name,color){
            this.food = food
            Cat.call(this,name,color) // this -> Dog
        }//构造函数继承
    Dog.prototype = Object.create(Cat.prototype)//原型继承

    let res = new Dog('water','耶耶','white')
    console.log(res)//Dog {food: 'water', name: '耶耶', color: 'white'}
    res.skill() //抓老鼠

    //构造器
    console.log(Dog.prototype.constructor);//fn Cat()

4.指正实例的构造器(分类)

  Dog.prototype.constructor = Dog
  console.log(Dog.prototype.constructor);//fn Dog()