js原型,我懂了

45 阅读3分钟

一、javascript中的继承

从对象角度讲,作为一门很像面向对象的语言,有对象就应该有类,但是js没有类的概念(ES6开始有了class,但是解析后也不存在类)。

也就是说,对于可以运行的js脚本,没有类。

如果没有类,js是如何创建对象的呢?

创建对象应该有构造函数constructor,也就是js的函数,一般构造函数首字母要大写(最好是大写,易于分辨)

通过new的操作符,就可以创建对象了,如图所示

function Shape() {
  this.x = 0;
  this.y = 0;
}

然后new一个对象出来,如图所示,

var s = new Shape()

先输出Shape,再输出s,如图所示

image.png

可以看到Shape看不出什么。 但是s很有意思,有一个 [[Prototype]]属性。这就是所谓的原型。js一切对象中都有这个属性,但是不能直接访问,大部分浏览器使用__proto__来访问。

其实 Shape 也有__proto__这个属性,更重要的是还有prototype属性,也叫原型,如图所示

image.png

但是只有函数才会有prototype,所有的对象只有一个隐式原型__proto__。 那么问题来了 这两个原型的区别是什么?

答: 1、prototype,也叫函数的原型对象,是(构造)函数存放对象实例共享的方法和属性的,可以理解为基类;

2、[[Prototype]],或者__proto__,也叫对象的原型,是对象继承父类存放属性和方法的。 ​

二、从继承挖掘原型

我们说到,函数声明就存在了prototype,那么对象的__proto__是怎么来的呢?

当然是继承啊,那么__proto__具体指的是什么呢?

这里新建一个子类,继承Shape,如图所示

// 绑定Shape的函数体,相当于super
function Rec(){Shape.call(this)}
// 继承Shape
Rec.prototype = Object.create(Shape.prototype);
// 函数原型对象都有constructor属性,指向构造函数本身,重新设置一下;但是箭头函数不存在constructor属性
Rec.prototype.constructor = Rec

输出一下Rec的prototype

image.png

这就完成了继承吗?让我们验证一下。

创建一个Rec类型的实例,var rec = new Rec()

输出一下

image.png

然后我们看到

rec.proto 很像是 Rec.prototype,

Rec.prototype.__proto__很像是Shape.prototype,

我们验证一下:

image.png

因此,得出结论,__proto__的确是跟继承密切相关。

当然这也引出了原型链---当查找对象属性的时候,先从实例中查找,如果实例不存在此属性,则从该对象的原型中查找,如果原型也不存在,则从原型的原型对象中查找,直到null,这个过程就形成了一个链,就叫做原型链。如图所示,原型链继续验证

image.png

那么问题来了,构造函数是函数,也是对象,那么(构造)函数的__proto__是什么呢? 答: js中一切函数都是Function类型的对象,也就是说函数都是Function来的,所以,如图所示

image.png

所以要注意

__proto__和prototype是两个完全不同的原型,不要搞混了。

所以,举一反三,js中的内置对象,比如Object、Array、Date等,实则也是一堆构造函数,也是来自于Function

image.png

讲到这里,我们只是说了原型一些之间的关系,那么原型和构造函数之间有关系吗?实例(对象)和他们之间呢?当然有。

前面说到,函数的prototype中有一个constructor指向自己,而实例原型中也有constructor,也就是其构造函数原型的constructor,因此就有如下结论了:

实例原型中的属性可以直接访问,所以

rec.constructor === rec.proto.constructor === Rec.prototype.constructor === Rec

验证一下

image.png

因此,举一反三,空数组[]

[].constructor === Array.prototype.constructor === Array

所以,new一个数组对象的时候,可以使用这样的技巧,

var arr = new ([].constructor)()
//[]

其他内置对象也有类似的用法,这是后话。 最后贴一张经典图

image.png