兜兜转转工作了也有快两年了,最终还是决定拾起当初的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 源码整体架构,打造属于自己的请求库
面不面试的,你都得懂原型和原型链
原型链继承图解