原型与原型链、

51 阅读4分钟

01_原型

  • 每一个函数 都有一个属于自己的原型
  • 作用: 我们会在原型内部放一些公共的方法, 目的不是为了让构造函数去使用, 而是为了让实例化对象去使用

02_万物皆对象

    /**
     *  JS 中, 万物都可以都可以称为对象
     *      对象: 
     *          含义1: 一种数据格式 {key: value, key2: value2}
     *          含义2: 某一类事务的实例 (某一类内容中的 真实个体)
     * 
     * 
     *      const arr = [1, 2, 3]
     *      const arr1 = [1, 2, 3, 4]
     *      const arr2 = [1, 2]
     *          这个 arr1 就是 Array 这一类内容中的 某一个 真实个体, 数组也可以算作一个对象(Array 这一类事务中的一个个体)
     * 
     *      const fn = () => {console.log(1)}
     *      const fn2 = () => {console.log(2)}
     *      const fn3 = () => {console.log(3)}
     *          函数也是一个对象(属于 Function 这一类事务中的一个个体)
     * 
     *  如果一个数据 [] 那么他就是Array 这个对象中的某一个个体
     *  如果一个数据 {} 那么他就是Object 这个对象中的某一个个体
     *  如果一个数据 function(){}   那么他就是 Function 这个对象中的某一个个体
    */

    const arr1 = [1, 2, 3]
    const arr2 = new Array(4, 5, 6)

03_原型链

    /**
     *  原型链
     * 
     *      查找对象的某一个属性:
     *          先在对象内部开始查找, 找到直接使用, 然后停止查找
     *          如果没有找到, 会找对象的 obj.__proto__, 如果找到直接使用, 然后停止查找
     *          如果这里没找到, 会继续去对象的 __proto__ 查找, 找到直接使用, 然后停止查找
     *          如果还是没找到, 会继续向上查找
     *          ...
     *          直到找到顶层作用对象    Object.prototype, 找到就是用, 找不到 undefined
    */
    function Person (name) {
        this.name = name
    }
    Person.prototype.sayHi = function () {
        console.log(100)
    }
    const p = new Person('QF001')
    // console.log(p)
    
    /**
     *  问题1: p 的 __proto__ 指向谁?
     *          + p 是 Person 的实例化对象
     *          + __proto__ 指向自身构造函数的原型
     *          + p.__proto === Person.prototype
     * 
     *  问题2: Person 的 __proto__ 指向谁?
     *      + Person 是构造函数, 本质上函数
     *      + 只要是一个函数, 他就是 Function 的实例
     *      + Person.__proto__ 指向了 他的构造函数的原型, 构造函数是 Function, 那么构造函数的 原型 Function.prototype
     *      + Person.__proto__ === Function.prototype
     * 
     *  问题3: Person.prototype 的 __proto__ 指向谁?
     *      + Person.prototype 其实就是  构造函数 Person 的原型对象, 本质上就是对象
     *      + 只要是一个 对象, 他就是 Object 的实例
     *      + Person.prototype.__proto__ 指向了 他的构造函数的原型, 构造函数 Object, 那么构造函数的原型 Object.prototype
     * 
     *  问题4: Function 的 __proto__ 指向谁?
     *      + Function 是构造函数, 本质上就是一个函数
     *      + 只要是一个函数, 他就是 Function 的实例
     *      + Function.__proto__ 指向了 他的构造函数的原型, 构造函数 Function, 那么 构造函数的原型 Function.prototype
     *      + Function.__proto__ === Function.prototype
     * 
     *  问题5: Function.prototype 的 __proto__ 指向了谁?
     *      + Function.prototype 其实就是 构造函数 Function 的原型对象, 本质上是对象
     *      + 只要是一个对象, 他就是 Object 的实例
     *      + Function.prototype.__proto__ 指向了 他的构造函数的原型, 构造函数 Object, 那么构造函数的原型 Object.prototype
     *      + Function.prototype.__proto__ === Object.prototype
     * 
     *  问题6: Object 的 __proto__ 指向了谁?
     *      + Object 是一个构造函数, 本质上还是一个函数
     *      + 只要是一个函数, 那么他的构造函数 就是 Function
     *      + Object.__proto__ 指向了他的构造函数的原型, 他的构造函数是 Function, 那么构造函数的原型 Function.prototype
     *      + Object.__proto__ === Function.prototype
     * 
     *  问题7: Object.prototype 的 __proto__ 指向了谁?
     *      + Object.prototype 是构造函数 Object 的原型对象, 本质上就是一个对象
     *      + 但是重点: Object.prototype 是 JS 顶层的对象
     *      + Object.prototype.__proto__ === null
    */
    

04_判断数据类型

     *  判断数据类型
     *      1. typeof   判断基本数据类型
     * 
     *      2. constructor 可以判断 当前数据的 构造函数 是谁
     *              问题1: 能够判断引用数据类型
     *                      但是! 这个属性其实就是对象内的一个属性
     *                      我们可以拿到这个对象, 然后修改他的属性值
     *              问题2: 不能判断 undefined 和 null
     * 
     *      3. instanceof 可以判断 左边的构造函数是否等于右边的构造函数
     *          语法: 检测的数据 instanceof 构造函数
     *          问题: 不能判断 undefined 和 null
     * 
     *      4. Object.prototype.toString.call(要判断的数据结构)
     *              Object 这个构造函数的 原型内部 有一个 toString 的方法
     *              这个方法能够帮我们将数据结构转为字符串的形式    '[object 数据结构]'
     * 
     *          我们在使用的时候 如果需要判断其他数据类型, 需要使用 .call这个方法改变内部 this 指向
     * 
     *          这个方法任何数据类型都能准确判断(推荐使用)
    */