美文网首页HTML5
原生js如何写一个类?

原生js如何写一个类?

作者: 陌客百里 | 来源:发表于2020-08-25 23:55 被阅读0次

    【序】今天又在翻看公众号:《前端大全》了,发现这样篇文章讲原生js的类的,讲的挺好的,就打算自己再借东风精简一下关键点,原文地址0

    一个类的主要组成部分有:类名,构造函数,属性,方法, 继承
    在typescript中是这样的↓

    import Vue from 'vue'
    class foo extend Vue{
    constructor(dogName:string){
      this.dog = dogName;
    }
      public dog:string = 'husky'
      public dogSay(value){
      console.log(`dog say:${value}`)
    }
    }
    

    相信大家很快就能够找到对应的部分,那么在js早期版本(指的是ES6之前的版本),是这么实现的呢?

    function Animal(){}
    
    function Dog(dogName){
      this.dog = dogName;
    }
    Dog.prototype.__proto__ = Animal.prototype
    Dog.prototype.dogSay = function(value){
      console.log(`dog say:${value}`)
    }
    
    let myFoo = new foo('wangcai')
    myFoo.dogSay('hello')
    

    现在再来对号入座,是不是感觉能看懂又觉得不太懂,所以就引入下列问题

    问题一

    • 【疑惑】构造函数哪里去了?
    • 【解惑】函数自身就成为构造函数

    问题二

    • 【疑惑】既然本身是个构造,那么属性和方法存在哪里?
    • 【解惑】属性和方法是在执行完函数后才生成的,因此挂载到为实例分配的空间上,而this指针指向的是未来创建的实例。

    问题三

    • 【疑惑】既然是存在未来的实例上,那么为什么方法要放到prototype中呢?
    • 【解惑】prototype可以理解为该类所创建的所有实例的共同的空间,如果放到this指针上,每生成一次实例都会多余分配一个函数所占用的空间,而放在prototype则在调用函数时才去prototype中取函数去执行。

    问题四

    • 【疑惑】 既然是公共空间那为什么每个实例调用到的方法,方法中的this都指向调用的实例?
    • 【解惑】 因为在js中this的指向都是谁调用就指向谁

    问题五

    • 【疑惑】既然prototype是个公共空间那么我们可以写如下代码吗?为什么?
    function foo(dogName){
      foo.prototype.dog = dogName;
    }
    
    • 【解惑】 如果是想要个普通的类属性的话,不可以,之前说过prototype是所有实例的公共空间,这样的话所有实例中的dog都改变了,但是可以作为类中的静态方法去使用

    问题六

    • 【疑惑】 为什么继承要使用proto指向父级的prototype?而不是直接指向父级Animal?
    • 【解惑】 首先,Animal本身是一个构造函数,在new操作之后,实际生成的实例指向的是构造器的prototype,而之前说过prototype是一个公共空间,因此,新创建出来的实例并不直接等同于构造器的prototype,而是使用指针proto指向了父级的prototype

    问题七

    • 【疑惑】 既然this指向实例,而实例不直接等同于prototype,那如何解释可以直接this到属性和方法?
    • 【解惑】 因为js的查找机制,如果this.dogSay 在this的prototype上找不到,那么就会沿着proto向上找,直到找到Object.prototype,如果都没有就返回null

    问题八

    • 【疑惑】为什么proto在实例上是dog.__proto__,而在继承时构造函数上则是Dog.prototype.__proto__ = Animal.prototype
    • 【解惑】 原理是实例的proto与原型的proto实际上是两个不一样的指向,实例dog的proto指向的是Dog.prototype,
      而方法Dog的prototype.proto指向的是构造器,在new的时候实际上调用的是Dog.prototype.proto,也就相当于dog.proto.proto,如果我们将Dog的真实构造器的指向父级,那么new 的时候会根据proto一直找到父级的构造器

    总结

    原文提出的细则总是难以理解,我学习时喜欢找到最基础的因素并向外推导,因此我们需要先找到会核心的元素,一个函数,从它开始推导。

    一个函数的组成部分:函数体,prototype空间,constructor构造器
    一个实例的组成部分:实例本身的内存空间,实例的公共空间,
    创建一个实例所需要的关键词:new
    好的接下来大家能不能将过程再还原回来?
    当我们new Dog()的时候发生了什么流程?
    1.搜索new 通过Dog.prototype.proto找到了构造器方法

    1. 通过构造器方法创建了新的实例内存空间,实例中都有一个特殊方法proto,指向了实例的公共空间prototype
    2. 当调用实例的属性时,js就会再实例的空间查找,找不到就会顺着proto的指向去查找,如果都没有该属性就会返回null

    相关文章

      网友评论

        本文标题:原生js如何写一个类?

        本文链接:https://www.haomeiwen.com/subject/wiutsktx.html