面向对象-构造函数-原型-检测数据类型

59 阅读6分钟

创建对象的方式

    1. 字面量的方式
    1. 内置构造函数的方式
  • 上述的两种方式都能够帮助我们创建对象, 但是不能帮助我们批量生产对象

    1. 工厂函数模式
    • 本质上就是一个函数, 函数内部帮助我们创建一个对象, 然后返回出来
    • 将来需要对象的时候, 我们直接调用函数即可
    1. 自定义构造函数
    • 本质上也是一个函数, 函数内部会帮助我们创建一个对象, 然后返回出来
    • 将来需要对象的时候, 我们直接调用函数即可

自定义构造函数的书写

  1. 构造函数的函数名 建议首字母大写 (为了和普通函数做一个区分)
  2. 构造函数将来在调用的时候, 必须和 new 关键字 一起使用 (必须这样写)
  3. 构造函数内部不需要书写 return
    • 如果 手动返回了 基本数据类型, 那么写了和没写一样
    • 如果 手动返回了 引用数据类型, 那么写了之后构造函数失效
  4. 构造函数在使用的时候 内部 的 this 规则和之前的函数不太一样 (重点!!!)
    • 因为一个函数要想当成构造函数去使用, 那么必须要和 new 关键字一起使用
    • 如果一个函数和 new 关键字一起使用, 那么内部的 this 就指向函数中被创建出来的对象
    • 构造函数内部的 this 指向于 函数内部自动创建出来的那个对象
  1. 构造函数不能使用箭头函数, 因为箭头函数内部没有 this

函数访问原型对象

  • 首先要明确一点, 原型是为了解决 构造函数的缺点而存在的, 就是构造函数内声明的函数提取到一个公共的地方

  • 我们JS中, 所有的函数一定有一个属性 prototype, 这个属性指向了一个对象, 我们将这个对象称之为 原型对象/原型/原型空间

  • 每一个原型对象中一定会有一个属性 constructor, 当前属性的属性值就是说当前原型对象是那个函数的

  • 注意点: * 我们可以通过 函数的 prototype 属性获取到这个函数的 原型对象, 获取到这个原型对象后, 我们可以向内部添加一些属性 * 属性的值 没有任何限制, 就和我们向一个普通对象中添加内容一样, 但是我们只推荐向内部书写 函数

      * 同时我们也要明确一个点, 就是我们添加的这个数据并不是给构造函数使用, 而是给当前的构造函数的所有实例化对象去使用的
    
  • 对象访问自己构造函数的原型对象

    • 每一个对象中 都有一个属性 proto (注意: 前后都是两个下划线, 一共是 四个)

    • 这个属性会指向自己当前构造函数的原型对象

    • 注意: 我们实例化对象可以通过 proto 获取到原型对象的内容, 但是我们一般不会书写 proto

      • 因为这个属性可以省略, 我们可以直接拿 实例化对象去调用当前构造函数的原型对象中的内容

万物皆对象

  • 对象的一个定义:

    1. 一种数据类型: { key: value, key2: value2 }
    2. 一类内容中的一个真实个体
  • 在 JS 中 只要是 数组[] 那么就属于 Array 这一类内容中的一个真实个体

  • 在 JS 中 只要是 函数function 那么就属于 Function 这一类内容中的一个真实个体

  • 在 JS 中 只要是 对象{} 那么就属于 Object 这一类内容中的一个真实个体

  • 原型链

    • 是关于对象内部属性的查找规则

    • 当我们在一个对象内部查找一个属性的时候, 会现在当前对象的自身查找

      • 如果找到直接使用并停止查找, 如果没有找到, 那么会去到当前对象的 proto 中继续查找

      • 如果找到直接使用并停止查找, 如果没有找到, 那么会继续去当前对象的 proto 中继续查找

      • 一直到最顶层的对象 Object.prototype, 还是没有找到, 那么返回一个 undefined

function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.sayHi = function () {
    console.log('下午好~~~')
}

const p = new Person('张三', 18)
// console.log(p)


console.log('1. ', p.__proto__ === Person.prototype)
console.log('2. ', Person.__proto__ === Function.prototype)
console.log('3. ', Person.prototype.__proto__ === Object.prototype)
console.log('4. ', Function.__proto__ === Function.prototype)
console.log('5. ', Function.prototype.__proto__ === Object.prototype)
console.log('6. ', Object.__proto__ === Function.prototype)
console.log('7. ', Object.prototype.__proto__, Object.prototype.__proto__ === null)

/**
 *  1. p.__proto__                      === ???
 *      p 其实就是一个 实例化对象, 构造函数是 Person
 *          p.__proto__ === Person.prototype
 *
 *  2. Person.__proto__                 === ???
 *      Person 是构造函数, 本质上就是一个函数
 *      在 JS 中, 只要是一个函数, 那么就是 Function 这个构造函数的 实例化对象
 *          Person.__proto__ === Function.prototype
 *
 *  3. Person.prototype.__proto__       === ???
 *      Person 是一个构造函数, 本质上就是一个函数
 *      Person.prototype        其实就是一个函数的原型对象      本质上就是一个对象
 *      所以 Person.prototype.__proto__ 其实就是指向了一个对象的构造函数的原型对象
 *      因为JS 中 对象的构造函数就是 Object
 *      所以我们可以得到一个等式 Person.prototype.__proto__ === Object.prototype
 *
 *  4. Function.__proto__               === ???
 *      Function 是 JS 中内置的一个构造函数, 本质上就是一个函数
 *
 *          所以我们现在其实就是在找一个函数的构造函数的原型对象,   因为函数的原型对象是 Function
 *              Function.__proto__ === Function.prototype
 *
 *  5. Function.prototype.__proto__     === ???
 *      Function    内置构造函数, 其实就是一个函数
 *      Function.prototype  指向了当前构造函数的原型对象, 本质上就是一个对象
 *
 *          所以我们现在本质上就是在找一个对象的 构造函数的原型对象是谁
 *
 *              Function.prototype.__proto__ === Object.prototype
 *
 *  6. Object.__proto__                 === ???
 *      Object  是 JS 中 一个内置构造函数, 其实就是一个函数
 *          现在就相当于在找一个函数的 构造函数的原型对象
 *
 *              Object.__proto__ === Function.prototype
 *
 *  7. Object.prototype.__proto__       === ???
 *      在 JS 中最顶层的对象就是    Object.prototype, 所以如果再向上找的话, 就找不到任何东西了
 *      然后 在 JS 中, 给我们返回了一个数据 null
 *
 *          Object.prototype.__proto__ === null
*/

判断数据类型

  1. typeof
  • 缺点: 引用数据类型判断的时候不太准确
  1. constructor
  • 语法: 数据.constructor === 构造函数

    • 我们可以通过 对比他等于那个构造函数, 然后确认他是那个数据类型
  • 缺点: undefined 和 null 不能使用

    • constructor 其实就是一个对象内部的一个属性, 是有可能被修改的
  1. instanceof
  • 语法: 数据 instanceof 构造函数

  • 缺点: undefined 和 null 不能使用

    • 引用数据类型, 有可能会被识别对 对象类型
  1. Object.prototype.toString.call(要判断数据类型的数据)
    • 能够判断 JS 中 所有的 数据类型