【序】今天又在翻看公众号:《前端大全》了,发现这样篇文章讲原生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找到了构造器方法
- 通过构造器方法创建了新的实例内存空间,实例中都有一个特殊方法proto,指向了实例的公共空间prototype
- 当调用实例的属性时,js就会再实例的空间查找,找不到就会顺着proto的指向去查找,如果都没有该属性就会返回null
网友评论