关于原型的个人总结
一、原型链的产生
参考:知乎 - 写代码的苏打饼
链接:JavaScript 世界万物诞生记
- 这张图片展示了JavaScript的结构发展(注:[ p ] 代表__proto__)
- 一开始是null,发展出了No.1对象,就是Object.prototype;
- 然后出现了制造对象的机器Object();
var obj = new Object(name:'obj');
-
但是通过
new Object()
制造的对象都是以Object.prototype为原型的,整个体系就显得单调。 -
机器(构造函数)是用来制造对象的,但是机器(构造函数)本身实际上也是一种特殊对象。
例如:Array()是一个构造函数,但是它的静态方法是存储在Array对象下面的,比如Array.isArray()
;
可以通过打印输出Array.prototype
来查看,Array.prototype的constructor属性指向了构造函数,可以看到它的下面有isArray
方法;
于是,基于No. 1(Object)对象,造出了一个No. 2(Function)对象,用它来表示所有机器的共同特征。换句话说,把它作为所有机器的原型对象。同时创造了制造机器的机器Function(),并且让所有的构造函数都是由Function()创建的; -
同时加入了 new 关键字,它的作用是:
- 创建一个空对象,this指向空对象
- 为空对象绑定原型prototype
- 执行构造函数的代码(为这个对象添加属性,属性和方法,都加入到了this所引用的对象中)
- 最后隐式(系统内部自动完成,不可见)返回this
这里我们应该注意到为什么new Object()
产生的对象都指向Object.prototype,而new 构造函数()
指向的就不是Object.prototype?
这是因为new Function()
出来的函数会自动添加一个prototype原型对象( 他上面的属性和方法只有一份并且所有实例共享;
这样整个原型的体系就形成了。。。
同时参考下图(完整的原型链):
二、原型链的一些规则总结
基础概念:
- 原型:
- 每个函数都有原型
- 原型是一个引用类型
- 原型上面的属性和方法都能被实例访问
- 将公有的属性和方法绑定在原型下面,提供给所有的实例和对象使用
- 显示原型:prototype ---- 构造函数定义方法时通常使用的属性,它指向了一个空对象,可以把类公有的方法或者属性定义在里面;
- 隐式原型:proto ---- 构造函数的实例拥有的属性;原型链上的对象正是依靠这个属性连结在一起。实例对象访问这个属性的操作可以认为是查找操作,具体解释见下文。
- instanceof: 用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。
规律总结:
- 隐式原型链就是查找链,作为一个实例对象,当你访问其中的一个属性或方法的时候,如果这个对象中(构造函数)没有这个方法或属性,那么Javascript引擎将会访问这个对象的__proto__属性所指向上一个对象,并在那个对象中查找指定的方法或属性,如果不能找到,那就会继续通过那个对象的__proto__属性指向的对象进行向上查找,直到这个链表结束。同时这个查找过程是隐式的,即浏览器内部帮助我们进行查找,实际上通过‘ . ’操作符进行查找。
- 显式原型链是定义链 ,构造函数通过 prototype 属性进行公共属性方法的定义。
- 实例对象的隐式原型指向构造函数的显式原型。这里比较特殊的是Function,它的显式原型和隐式原型都指向它自身,就可以理解为他是通过 new自己产生的(“一脸茫然(>.<)”)。Function的内部实现是通过c++等实现的,就是说JavaScript的解释器是用c++等编写的;
- es6 的 class 语法糖:内部是通过JS原生代码实现的,我们可以定义一个ts文件使用TS语法定义一个类,然后定义一个实例,通过转义器编译成JS代码,可以看出完全就是由js实现的;
结语
- js的原型是JavaScript编程的核心之一,透彻的了解它,可以更深层次的理解其他前端开发工具,框架等;
- 文中如有不对的地方可以私信作者(^_^);