js之原型继承历史由来
image.png灵儿的小感慨:
学技术如果只是老是想着如何把工作完成,被赶鸭子,真的好累。如果多读些关于它的前世今生,从原理上去理解,它是什么,为何产生,为了解决什么问题,能做什么,然后再具体去实现功能,感觉会好很多。
js是怎么产生的
一开始,我们浏览器的网页只能浏览内容,是不能交互的。包括用户名密码输入这些都是由服务端来判断,这种设计非常浪费时间和服务器资源。
为了解决这个问题,需要开发一种运行在浏览器中的脚本语言,用来简单的做用户输入校验等操作。
当时最流行的语言是面向对象的Java编程语言 ,为了能够借助 Java
将浏览器脚本语言流传开,所以起名 JavaScript
。其实两者没有任何的关系。
数据类型设计引发继承思想
JS 中的数据类型设计受当时 Java
流行的影响,都是对象类型,这时候就遇到问题了,有对象必然涉及到继承机制,那么 JS
的继承机制要设计成 Java
一样呢?还是另有设计思想?
js的继承设计思想
JS 的开发者想如果设计成像 Java一样有“类”的概念岂不是和 Java
一样成为了一种完全面向对象的编程语言了?最后决定自己设计一种继承机制,但是它的设计思想还是采用了 Java
的一些特性。
1. 如何生成一个对象
通常 Java
生成对象是通过 new
的方式,通过类生成一个实例对象的过程。但是 JS 中并没有类,那 JS 的设计者要怎么做?
他找到了 Java 和 JS 的共同点就是两者都有构造函数, Java的 new
的过程内部其实调用了构造函数。但是 JS 是没有“类”的概念的,于是 JS 就把 new
一个“类”设计成了 new 一个构造函数,于是构造函数成为了一个实例对象的原型对象。
2. 原型对象的升级
上述这样的原型设计有一个致命的缺点:无法共享公共属性。
所以要设计一个对象专门用来存储对象共享的属性,那么我们叫它「原型对象」。
原型对象是啥
要想让构造函数生成的所有实例对象都能够共享属性,那么我们就给构造函数加一个属性叫做 prototype
,用来指向原型对象,我们把所有实例对象共享的属性和方法都放在这个构造函数的 prototype
属性指向的原型对象中,不需要共享的属性和方法放在构造函数中。
对象和函数在原型链关系?
构造函数的 prototype
指向原型对象,原型对象有一个 constructor
属性指回构造函数,每个构造函数生成的实例对象都有一个 _proto_
属性,这个属性指向原型对象。
原型链
原型链是什么?顾名思义,肯定是一条链,既然每个对象都有一个 _proto_
属性指向原型对象,那么原型对象也有 _proto_
指向原型对象的原型对象,直到指向上图中的null,这才到达原型链的顶端。
总结
- 之所以会有构造函数、原型、原型链,就是因为我们要实现属性公用、实现继承。
- 实例,就是new一个构造函数返回的这个新的对象,这个实例继承了构造函数的原型对象。这样来说,构造函数就是原型了。
- 原型链,就是每个对象的属性
_proto_
一直链道顶端Object的_proto_
,继而指向null。
注:
- 构造函数就是专门用来生成对象实例的函数(模板),构造函数需大驼峰书写。
- 每个构造函数,都会有一个
prototype
属性。 - 只要是对象,都会有一个内置属性叫做
_proto_
。_proto_
属性指向的是原型对象。