兜兜转转工作了也有快两年了,最终还是决定拾起当初的js基础。
毕竟完全理解它才能更加深入前端这个行业,技术才能有更大的突破。
本文是重学基础的第一篇,关于原型和原型链。
开始
最近想尝试阅读一下axios的源码,参考大佬的架构文章,在看到第一个函数时就有点吃力 😓。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | function createInstance(defaultConfig) {   const context = new Axios(defaultConfig);
    const instance = bind(Axios.prototype.request, context);
       utils.extend(instance, Axios.prototype, context, {allOwnKeys: true});
       utils.extend(instance, context, null, {allOwnKeys: true});
       instance.create = function create(instanceConfig) {     return createInstance(mergeConfig(defaultConfig, instanceConfig));   };
    return instance; } const axios = createInstance(defaults)
  axios.xxx = xxx 
 
 
 
  | 
 
平常在使用的时候就发现,axios导出的实例有非常多的写法以及api。
axios.post()
axios()
axios.create
似乎是更改了实例的原型链关系。

图片来源 学习 axios 源码整体架构,打造属于自己的请求库
概念
- 原型
js当中,每一个对象(除了null)都会有一个关联对象,像是父子关系,它就是原型。
对象都会从原型上面继承它的属性。 
- 原型链
连续关联的原型即是原型链。
比如A -> B -> Object 
- 基础类型和引用类型
基础类型和引用类型的区别就是在堆栈中的存储方式不同。
基础类型存储的是他的值。
引用类型存储的是他的值的引用。
比如下面这样 
1 2 3 4 5 6 7 8 9 10
   | var a = 100  var b = a  a = 200  console.log(a, b) 
  var objA = { a: 100 } var objB = objA  objA.a = 200 
  console.log(objA.a, objB.a) 
 
  | 
 
- __proto__
所有的引用类型都有一个__proto__属性,一个普通的对象。

 
1 2 3 4
   | {   constructor: xxx,   __proto__: xx }
 
  | 
 
- prototype
__proto__指向向了它的构造函数的prototype属性

 
根据上面的图可以看到const obj = {}的__proto__指向的就是构造函数Object的prototype
当试图去获取一个当前值上不存在的某个属性时,它会去它的__proto__上找,一直往上,直到为null为止(最顶层为null)。
每个对象都有__proto__对象,只有函数对象才会有prototype对象。
构造函数的原型链关系
记录一下完整的构造函数的原型链关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | class Parent {
    name = "parent"
    getName() {     return this.name    }
  }
  class Child extends Parent {
    name = "child"
  }
  const parent = new Parent() const child = new Child() 
  console.log(parent.__proto__ === Parent.prototype)  console.log(child.__proto__ === Child.prototype)  console.log(child.__proto__ === Parent.prototype)  console.log(Child.prototype === Parent.prototype)  console.log(Child.__proto__ === Parent)  console.log(Parent.prototype.__proto__ === Object.prototype) 
 
 
  | 
 
图片来源 轻松理解JS 原型原型链
小练习
- parent.proto === Parent.prototype
 
  点击显示答案
  true
   
- child.proto === Child.prototype
 
  点击显示答案
  true
 
- Child.proto === Parent
 
  点击显示答案
  true
 
- Parent.prototype.proto === Object.prototype
 
  点击显示答案
  true
 
- Parent.prototype.constructor === Parent
 
  点击显示答案
  true
 
- Object.prototype.proto = ?
 
  点击显示答案
  null
 
- Function.prototype.proto = ?
 
  点击显示答案
  Object.prototype
 
继承
1 2 3 4 5 6 7 8 9 10 11 12 13
   | function Parent(name) {   this.name = name  } Parent.prototype.say = function() {   console.log(this.name) } function Child(name, subName) {
  }
  Child.prototype = new Parent()
  Child.prototype.constructor = Child 
 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | function Parent(name) {   this.name = name  } Parent.prototype.say = function() {   console.log(this.name) } function Child(name, subName) {         Parent.call(this, name)   this.subName = subName }
  Child.prototype = new Parent()
  Child.prototype.constructor = Child 
 
  | 
 
总结
四准则
- js分为函数对象和普通对象,每个对象都有__proto__属性,但是只有函数对象才有prototype属性
 
- Object、Function都是js内置的函数, 类似的还有我们常用到的Array、RegExp、Date、Boolean、Number、String
 
- 属性__proto__是一个对象,它有两个属性,constructor和__proto__
 
- 原型对象prototype有一个默认的constructor属性,用于记录实例是由哪个构造函数创建
 
结束
结束🔚。
参考资料
轻松理解JS 原型原型链
做了一份前端面试复习计划,保熟~
学习 axios 源码整体架构,打造属于自己的请求库
面不面试的,你都得懂原型和原型链
原型链继承图解