写在前面:这篇文章是我在掘金的第一次,更是有史以来第一次写这种非表面知识的个人理解。肯定会有理解不到位甚至是错误的地方,希望大家带有批判性的阅读。有认为不合理的地方,尽管提出来~
说到原型,相信现在处于懵逼状态的人还是挺多的。
什么是原型?
什么是原型链?
__proto__是什么?
prototype又是什么?
__proto__和prototype有什么区别?
上边这些问题,在之前我也一直挺懵的,即使到现在,我也不敢说我完全弄明白了。所有接下来的东西如果大家觉得写的有什么问题,尽管提出来,大家一起进步。
这几天看了不少文章,查了资料,终于对于__proto__和prototype有了一点自己的头绪,废话少说,正文开始。
首先要知道我们为什么要搞懂 原型,它在我们平时写代码的时候有什么用。有人说原型是高阶编程必须的东西,比如说你要写框架,对JS原生的Object或者Array进行改造,那就需要在原型上进行。举个栗子,Vue里我们定义数组和JS原生形式没什么不一样,但是Vue中数组的push、pop等方法可以触发Vue的双向绑定,就是因为尤大对这些方法进行了封装。
但是对我们来说,平时用到原型最多的地方还是通过构造函数进行实例化对象。这个过程在面向对象语言中通过class来实现。但是在es6之前,JS中没有class的概念,而且ES6的class也不过是语法糖,本质上还是通过原型来实现的。
先提出四个概念以及它们分别是什么:
- 构造函数:用来构造对象的构造器,跟普通函数没有本质区别
- 实例对象:就是一个对象
- __proto__:每个对象拥有的私有属性
- prototype:构造函数的原型对象
下面我们就分别展开来说
- 实例对象的__proto__
每个对象都有一个 constructor 属性,可以得到它的构造函数。
所以可以得到:
function f(){}
let o = new f()
o.__proto__ === o.constructor.prototype //true- 函数的__proto__
- 构造函数的prototype
既然prototype得到的一个对象,那它理论上也应该有 __proto__ 属性。经过验证(大家自行进行吧~),它确实是存在。其实也不难理解,既然prototype是原型对象,那对象的__proto__指向的就是对象构造器的prototype,即 Object.prototype。
从图中可以看到,这种情况下,原型上的属性不能被访问到,这就是所谓的”属性遮蔽“。
- 使用语法结构
let obj = {a: 1, b:2}
//原型链:obj -> Object.prototype -> null
let arr = [1,2,3]
//原型链:arr -> Array.prototype -> Objec.prototype -> null
//因为Array构造器的原型对象(prototype,也是一个对象)是通过Object构造器生成的
//因此多了Object.prototype这一环
//Object.prototype的__proto__为null,所以原型链终止- 自定义构造函数
- Object.create
let a = {a: 1}
let b = Object.create(a)
let c = Object.create(b)
c.a //1
//原型链:c -> b -> a -> Object.prototype -> null- class 关键字
class area{
constructor(width, height){
this.width = width;
this.height = height
}
getArea(){
return this.width*this.height
}
}
let areaInstance = new area(10,20)
//原型链:areaInstance -> area.prototype -> Object.prototype -> null关于class的具体内容,后边会有一篇文章单独介绍。
es6的class是什么?
class和构造函数方式有什么区别?
class如何实现继承?
最后附一张自己画的原型结构关系图: