1 构造函数、原型对象和实例的区别
构造函数
就是函数的定义。在js中,每一个函数都会有prototype属性,指向该函数对应的原型对象。图一中,第二列的function指向第三列的prototype,均为函数通过prototype属性去指向的。
原型对象
每一个构造函数,在被定义的时候,就会创建一个原型对象。原型对象与构造函数之间通过函数的prototype属性和原型对象的constructor属性互相关联。即为图一中第二三列所表示的。
实例
通过构造函数new出来的对象。该对象会包含一个指针 [ [ prototype ] ] ,浏览器中定义了一个__proto__属性,来指向原型对象。图一中第一列的实例均通过指针__ proto __指向构造函数的原型对象。
区别总结
图二更直接地展示构造函数、原型对象和实例之间的关系。
构造函数定义的时候,就会产生原型对象,构造函数的prototype属性指向原型,原型的constructor属性。
使用构造函数new一个实例对象时,实例对象的__ proto __属性指向原型,constructor属性指向构造函数。
2 区分__ proto __ 和prototype
隐式原型
隐式原型,js中,万物皆对象,对象皆有属性__ proto __。这个属性指向构造该对象的构造函数的prototype。
不管是实例、构造函数还是原型对象,都是对象,所以都应该考虑它们的__ proto __属性指向什么对象。
Note: Object.prototype 这个对象是个例外,它的__proto__值为null
以不同方式创建的对象的__ proto __指向
- 字面量方式
字面量方式实质上是一种语法糖,本质是var o=new Object();o.xx=xx;o.yy=yy;
所以__ proto __指向为Object.prototype - new的方式
__ proto __指向new之后的函数的prototype - ES5中的Object.create()
create的实现:
function create(o){
function F(){}
F.prototype = o;
return new F()
}
这个时候的原型就指向o,因为构造函数F的prototype就指向o。
构造函数的隐式原型
既然是构造函数那么它就是Function()的实例,因此也就指向Function.prototype,比如 Object.__ proto __ === Function.prototype。见图一中的图例。
显式原型
function是一个特殊的对象,除了具有__ proto __ 属性之外,还有自己特有的属性————原型属性(prototype),指向原型对象。
也就是说每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。
Note:通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。
二者关系
隐式原型指向创建这个对象的函数的prototype。
3 原生对象的原型
所有原生引用类型(Object,Array,String等),都在其构造函数的原型上定义了方法。
可以给原生对象的原型,添加属性方法。
String.prototype.startsWith=function(text){
return this.indexOf(text)==0;
}
基本类型:undefined null Boolean Number String
引用类型:Object Array Date RegExp Function 基本包装类型(Boolean Number String) 内置单体对象(Global Math)
基本包装类型,在读取一个基本类型的时候,后台就会创建一个对应的基本包装类型对象。
其中10个函数类型( String,Number,Boolean,Array,Function,Date,RegExp,Error,Object,Event )函数类型 有 __proto__和 prototype 属性
而每一个对象都具有__ prototype __属性。
在浏览器里验证:
4 关于继承
一张图片解释父子继承关系。
图四中构造函数具有prototype属性,对于继承而来的函数,该属性指向一个父亲实例对象。
文章参考:
1.JavaScript instanceof 运算符深入剖析
2.https://www.zhihu.com/question/34183746/answer/59043879
3.《JavaScript高级程序设计》