一、首先谈谈原型
每个对象都有个属性prototype,名为原型,是一个指针属性,该属性指向一个原型对象;
而原型对象也有一个指针属性constructor,该指针指向原型对象的实例的构造函数;
构造函数实例化之后的实例则是存在_proto_属性,该属性指向构造函数的原型对象;(重点)
实例的constructor == prototype.constructor;
二、原型链
接下来用一段形象的话记录我对原型的感悟:
把构造函数看成是一个人,然后prototype是人的一个属性:基因,该基因指向一个细胞,也就是原型对象,而细胞也有一个属性,叫做组织属性(constructor),使用这个属性,细胞就可以组织成一个人,所以说原型对象(细胞)的constructor(组织)指向构造函数(人);所谓继承,也就是将细胞的基因传给子代,即实例是一个子代,实例的属性来自上一代的细胞里的基因;从而实现了继承;
使用代码更清晰:
Object.prototype.foo ="abc"; function f1(){}; var f2 = new f1(); console.log(f2.foo);//abc
简单点,在Object的原型上定义了foo属性,函数声明定义了f1函数,f2是构造函数f1的实例,看输出:
1.输出f2.foo为abc,继承路径:f2寻找,无;f1.prototype寻找,无,Object.prototype寻找,abc;
实际路线:f2._proto_指向f1.prototype, f1.prototype._proto_指向object.prototype;
2、如果输出f1.foo,也是abc;
注意:f1的foo属性并不是从f1.prototype中来的,而是f1自身没有,然后f1._proto_指向Object.prototype;从而得到foo;约等于f1 = new Object();
而外知识:Object.getOwnPropertyNames(function);返回数组包含除prototy中属性以外的所有属性名;
疑点解惑:
Object.__proto__ === Function.prototype //true;
Object是函数对象,由 new Funciton所创建;
Function.__proto__ === Function.prototype //true
同理Function也是对象函数,也是由new Function创建而来;
Function.prototype.__proto__ === Object.prototype // true
function.prototype是函数对象,在js里万物都是对象,因此,认个祖宗
Object.prototype.__proto__ ===null
原型链结束
原型链继承的精华是__proto__.
三、类式继承
function parent(){ this.name = 'HuaHua'; } parent.prototype.getName=function(){ return this.name; } var son = new parent(); console.log(son.getName()); //'HuaHua'
缺点:虽然继承了父类的原型的方法,但是没有继承父类的属性。
(2018/04/17)补充:
关于许多原型继承都在原型上定义方法的原因,是因为后面的所有实例的方法都指向原型,可以节省内存。