原型链模式(继承在内置类的原型上扩展方法)
构造函数模式虽然实现了我们的批量生产和实例识别,但是不能把一些方法提取成公有的方法
基于构造函数模式的原型链模式
function CreateJsPerson(name) { this.name = name; this.b = function () { console.log(this); } } //我们只需要把需要共有的属性写在类的prototype上即可 CreateJsPerson.prototype.writeJs = function () { console.log("my name is " + this.name + ",i can write javascript!"); }; CreateJsPerson.prototype.b = function () { console.log(this); }; //console.dir(CreateJsPerson.prototype); var p1 = new CreateJsPerson("A同学"); var p2 = new CreateJsPerson("B同学");
console.log(p1.writeJs == p2.writeJs);//-->true writeJs是每一个实例共有的属性
p1.b();//-->私有的
实例.属性名 的查找过程:首先找私有的属性,私有的存在,获取的就是私有的值,如果私有的不存在,在通过__proto__继续找公有的,如果有就是公有的,如果在没有,继续通过__proto__往上找...一直找到基类Object.prototype为止,如果基类上也没有,获取的属性值是undefined ------>原型链模式
console.log(p1.b == p2.b);//-->false
console.log(p1.__proto__.b == p2.__proto__.b);//-->true
console.log(CreateJsPerson.prototype.writeJs == p2.writeJs);//-->true
console.log(CreateJsPerson.prototype.b == p2.b);//-->false
p1.b();//this-->p1
p1.__proto__.b();//this-->p1.__proto__
CreateJsPerson.prototype.b();//this-->CreateJsPerson.prototype
console.log(CreateJsPerson.prototype===p1.__proto__);//true
规律:
1、每一个函数都有一个天生自带的属性 prototype(这个属性存储的值是一个对象数据类型),并且浏览器会默认的给这个属性开辟一个堆内存
在浏览器默认开辟的这个堆内存中,有一个天生自带的属性 constructor,这个属性指向当前类本身
console.log(CreateJsPerson.prototype.constructor);//-->CreateJsPerson
2、每一个对象都有一个天生自带的属性 __proto__,这个属性指向当前所属类的 prototype
console.dir(p1.__proto__.writeJs);
console.log(p1.hasOwnProperty === p1.__proto__.__proto__.hasOwnProperty);//-->true
console.log(p1 instanceof CreateJsPerson);//-->true 因为p1就是通过new CreateJsPerson创建出来的实例
console.log(p1 instanceof Object);//-->true 因为不管通过__proto__找多久,最后总会找到基类Object的prototype
通过构造函数模式创建一个实例,那么这个实例就继承了这个类中的所有的属性(私有的属性和公有的属性)
私有的属性是直接的存储到自己的内存空间中
公有的属性是通过自己天生自带的__proto__找到所属类的prototype