原型对象,class类,原型链,判断数据类型

54 阅读4分钟

原型对象

函数访问原型对象

  • 我们JS中,所有的函数一定有一个属性 prototype, 这个属性指向了一个对象,我们将这个对象称之为 原型对象/原型/原型空间
  • 每一个原型对象一定会有一个属性 constructor, 当前属性的属性值就是说当前原型对象是那个函数的
  • 注意点:我们可以通过 函数的prototype 属性获取到这个函数的 原型对象,获取到这个原型对象后,我们可以向内部添加一些属性,属性的值没有任何限制,就和我们向一个普通对象中添加内容一样,但是我们只推荐像内部书写函数
  • 对象访问子级构造函数的原型对象,每一个对象中,都有一个属性__proto__(注意:前后都是两个下划线,一共是四个),这个属性会指向子级当前构造函数的原型对象
  • 注意:我们实例化对象可以通过__proto__获取到原型对象的内容,但是我们一般不会书写__proto__, 因为这个属性可以省略,我们可以直接拿 实例化对象去调用当前构造函数的原型对象中的内容
function Person(name, age) {
    this.name = name
    this.age = age
}
console.log(Person)      // ƒ Person(name, age) { this.name = name; this.age = age }
console.log(Person.prototype)   // {constructor: ƒ}
console.log(Person.prototype.constructor)   // ƒ Person(name, age) { this.name = name; this.age = age }
Person.prototype.qwe = 'SHAO'
Person.prototype['你好'] = 'shaozhou'
Person.prototype.id = 1000
Person.portotype.good = true
Person.prototype.str = [1, 2, 3]
Person.prototype.sayHi = function () {
            console.log('你好')
        }
console.log(Person.prototype)   // { constructor: ƒ, qwe: 'QF001', asd: 'QF002' }  
const p1 = new Person('张三', 18)
console.log(p1) // { name: '张三', age: 18 }
console.log(p1.qwe)  // 'QF001'
console.log(p1.__proto__)   // {qwe: 'QF001', asd: 'QF002', a: 10086, b: true, c: Array(3), …}
console.log(p1.__proto__.qwe)   // 'QF001'

ES6 class类

  • 构造函数的缺点
      1. 构造函数在调用的时候可以不去书写new,只不过效果不对而已
      1. 构造函数和原型需要分开书写
  • 在ES6 之前, 我们在开发的时候,都是书写,构造函数,但是ES6之后,都改为class类
class '当前的类名' {}

class Person {
    // 构造器,功能和 构造函数的函数体 完全一样
    constructor (name) {
        this.name = name
        this.age = 18
    }
    // 当前位置开始,以下全都是类似于构造函数原型的位置
    // sayHi: function () {} // 这样书写 有报错
    sayHi () {
        console.log(123)
    }
    fn () {
        console.log('你好')
    }
}
const p1 = new Person('张三')
console.log(p1)
p1.a()
p1.sayHi()

原型链

  • 在 JS 中 只要是 数组 [] 那么就属于 Array 这一类内容中的一个真实个体
  • 在 JS 中 只要是 函数function 那么就属于 Function 这一类内容中的一个真实个体
  • 在 JS 中 只要是 对象{} 那么就属于 Object 这一类内容中的一个真实个体
  • 原型链:
    • 是关于对象内部属性的查找规则,当我们在一个对象内部查找一个属性的时候, 会现在当前对象的自身查找,如果找到直接使用并停止查找, 如果没有找到, 那么会去到当前对象的 _ proto_ 中继续查找,如果找到直接使用并停止查找, 如果没有找到, 那么会继续去当前对象的 _ proto_ 中继续查找,.......一直到最顶层的对象 Object.prototype, 还是没有找到, 那么返回一个 undefined
function Person () {
    this.name = 100
}
Person.protoype.age = 18
const p1 = new Person()
console.log(p1.age) // 18
console.log(p1.age_100) //undefined

判断数据类型

  • 1.typeof
    • 缺点: 引用数据类型判断的时候不太准确
    1. constructor
    • 语法: 数据.constructor ===构造函数
    • 我们可以通过 对比它等于那个构造函数,然后确定他是那个数据类型
    • 缺点: undefined 和 null 不能使用
    • constructor 其实就是一个对象内部的一个属性,是有可能被修改的
    1. instanceof
    • 语法: 数据 instanceof 构造函数
    • 缺点: undefined 和 null 不能使用,引用数据类型有可能会被识别对象类型
    1. Object.prototype.toSting.call(要判断数据类型的数据)
    • 能够判断JS 中 所有的数据类型
console.log(Object)  // 一个内置的构造函数
console.log(Object.prototype)    // 构造函数的原型对象
console.log(Object.prototype.toString)   // 原型对象中的一个属性, 值是一个函数
console.log(Object.prototype.toString.call([]))  // 调用了 函数的 call 这个方法, 修改了 前边函数内部的 this



console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call(100))
console.log(Object.prototype.toString.call('100'))
console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(null))
console.log(Object.prototype.toString.call(function () { }))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call(/\d/))