肚子饿?那就造个面馆吧

106 阅读5分钟

面向对象是什么?

  • 首先要明确, 面向对象不是语法, 是一个思想, 是一种 编程模式
  • 面向: 面(脸), 向(朝着)
  • 面向过程: 脸朝着过程 ---> 关注着过程的编程模式
  • 面向对象: 脸朝着对象 ---> 关注着对象的编程模式
  • 实现一个效果
    • 在面向过程的时候, 我们要关注每一个元素, 每一个元素之间的关系, 顺序...
    • 在面向过程的时候, 我们要关注的就是找到一个对象来帮我做这个事情, 我等待结果
  • 例子: 我要吃面条
    • 面向过程
      • 用多少面粉
      • 用多少水
      • 怎么和面
      • 怎么切面条
      • 做开水
      • 煮面
      • 吃面
    • 面向对象
      • 找到一个面馆
      • 叫一碗面
      • 等着吃
    • 面向对象就是对面向过程的封装
  • 我们以前的编程思想是: 每一个功能, 都按照需求一步一步的逐步完成
  • 我们以后的编程思想是: 每一个功能, 都先创造一个 面馆, 这个 面馆 能帮我们做出一个 面 (完成这个功能的对象), 然后用 面馆 创造出一个 , 我们只要等到结果就好了

创建对象的几种方式

  • 面向对象实际上就是寻找对象的过程(Object)

1、 字面量

    let obj = {
        key: 'value'
    }

2、内置构造函数

    let obj = new Object()
    obj.key = 'value'

3、工厂函数

  • 1、手写一个工厂函数
    • 该函数可以创建一个对象并且可以添加一些属性 并返回创建的对象
  • 2、利用工厂函数创建对象
        function createObject (a, b) {
                let obj = {}
                obj.name = a
                obj.age = b
                return obj
            }
        let obj = createObject(zh, 18)
        let obj = createObject(zhh, 28)
    

4、手写一个构造函数(必须和new关键字连用)

    1. 先书写一个构造函数
    • 在函数内添加一些属性
        function myObject (name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
    
  • 2、使用自定义构造函数创建对象
    let obj = myObject('zh', 18, 'boy')
    let Obj = myObject('zh', 18, 'boy')
  • 注意
    • 1、 自定义构造函数必须和new关键字连用
    • 2、 不要手写return手写return基本数据类型 相当于没写return 引用数据类型 构造函数会返回该数据且失去构造功能
    • 3、也就是自定义构造函数的缺点 会造成空间浪费
         function myObject (name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
    
    ``` js
        let obj = myObject('zh', 18, 'boy')
        let obj1 = myObject('zh', 18, 'boy')
        console.log(obj === obj1)//false 创建两个功能数据一样的对象 但是却在堆内存中有多个地址 造成了浪费
    

原型

  • 每一个函数都有自己的原型(原型对象)
  • 我们可以在原型上添加一些方法
  • 不然构造函数只能给对象添加属性, 不能合理的添加函数就太 low 了

prototype每一个函数天生自带一个prototype prototype 就是一个对象空间

        function fn() = {}
        console.log(fn.prototype)//对象 Object
  • 我们可以在原型空间内添加一些方法 或者储存一些属性 给函数原型添加不是给函数添加
  • 既然函数有原型(prototype) 对象也有天生自带的属性**的(proto)属性该属性指向自己的构造函数的原型 -对象的访问规则 假如object.key在自己内部没有找到 则会延着**的__proto__继续向上查找 找到就使用 没有找到的话则会继续向上查找 直到Object.prototype 因为其是js的顶级构造函数(万物皆对象)
  • 实际上一个对象的__proto__和自己构造函数的prototype属性是相等的 所以函数原型内部也有__proto__属性 且也是指向Object.prototype

02_万物皆对象

  • 在js中万事万物都可以称为对象
    • 第一层含义 就是单纯的指object也就是数据类型
    • 第二层含义就只某一类事物的实例(个体) 比如函数 function myfn() {} 就是Function中的某一个个体

03_原型链

  • 每一个对象都有自己的构造函数
    • 比如数组的构造函数Array 对象的构造函数 Object 函数的构造函数 Function
    • 有构造函数 就有原型 就有prototype 也就有__proto___
    • 当有一个位置实例个体时 我们可以把它当成Object的实例化对象
      • 因为所有个体 最终都会指向Object.prototype 继续往上就为null了

访问规则

  • 访问一个对象的成员时, 自己没有就会去 __proto__ 中找
  • 接下来就是, 如果 __proto__ 里没有就再去 __proto__ 里面找
  • 一直找到 Object.prototype 里面都没有, 那么就会返回 undefined

04_判断数据类型

判断数据类型的方法

  • typeof(要判断的数据类型)
    • 判断基本数据类型
    • 无法判断引用数据类型
  • 引用数据类型的判断方法
    • 1、constructor 可以判断当前数据的构造函数
      • 优点:能判断数据类型
      • 缺点:constructor不能判断undefind he null constructor其实就是对象内的一个属性
        let arr = [1, 2, 3]
        console.log(arr.__proto___constructor === Array) //true
    
    • 2、instanceof 可以判断 左边的构造函数是否等于右边的构造函数
      • 缺点:不能判断undefined和null数据类型
      • 语法:检测的数据 instanceof 构造函数
              let arr = []
              console.log(arr instanceof Array)//true
      
    • 3、Object.prototype.toString.call()
      • 优点:能判断任何数据类型 精确判断出数据类型
      • 原理:Object这个构造函数内部有一个toString()方法 能够将数据结构转为字符串的形式 我们在使用的时候 如果需要判断其他数据类型, 需要使用 .call这个方法改变内部 this 指向