原型
绝大多数对象最终都会继承自Object.prototype
特例 用 **Object.create(原型); 这个方法构造出来的对象
定义**
原型prototype是function对象的一个属性 同时原型prototype也是对象
它定义了构造函数制造出的对象的公共祖先
原型prototype这个对象在函数定义时就也被定义好了 一开始是一个空对象(但是里面有系统定义的属性)
然后可以往里面添加属性方法 如 Person.prototype.name = ‘haha’;
那么通过该构造函数产生的对象 可以继承该原型的属性和方法
特点
利用原型特点和概念 可以提取共有属性 来减少代码的冗余
对于后代继承的父类属性和方法 若后代重写了 会覆盖父类的方法
原型的增删改查
不能通过后代的对象来进行增删改查 这只会作用在后代对象的身上 不会影响到原型对象
要想实现原型的增删改查 只能通过对原型自身来进行增删改查
对象的构造函数constructor
每一个函数定义时原型就被定义好了 原型看似是个空对象
但是系统给原型定义了constructor属性 其对应的就是创建出来的函数
如 function Car( ) { } 那么这个函数的原型中constructor属性的属性值就是Car( )
我们也可以人为的改变Car函数的constructor 这个改变导致因其创建出来的对象的constructor属性也会发生改变
如 Car.prototype.constructor = ‘Person’
也可以人为的改变通过Car函数创建出来的car对象的constructor 这个改变不会印象到Car函数本身
如 car.constructor = ‘Person’
隐式属性 proto(相当于私有属性 尽量别修改 但是其实也能修改)
这也是系统给原型定义的proto属性 里面装的是原型
假设 var person = new Person();
对于用new来构造Person对象时发生的三段式中 第一段会在函数体的最前面隐式的加一个this{ }
这个this{ }看似是空的 里面其实装了 proto : Person.prototype
这起到的是连接person对象和原型的作用
如果访问person的属性时 属性不存在 那么就会沿着 proto 的指向 去Person.prototype上找有没有这个属性
如果人为的改变person的proto属性 那么它的指向就会发生改变
如 person.proto = obj; 那么此时 proto 的指向就指向的时obj
例
//结果为sunny
// function Person(){
// 隐式的加上 this = {proto : Person.prototype}
// }
// 可以这么理解 Person.prototype = { name:’sunny’ };
// proto : Person.prototype;
// Person.prototype = { name:’haha’ };
// Person.prototype = { name:’haha’ } 相当于换了个新的原型
// 但是 proto 中指向的还是原来的原型 所以输出结果是sunny
// 注意这里是先new对象再修改值 若是先修改值再new对象(把新原型那段代码放到new前面) 结果就是haha
原型链
当每个对象的原型都链接着某个父类对象 这些父类又都会链接到最终的原型Object.prototype 此时就构成了原型链
如
function Animal(){}
var animal = new Animal();
Person.prototype = animal;
function Person(){}
var person = new Person();
//此时person的原型就指向了animal animal的原型指向最终原型Object
Object.create();
也可以用这种方法创建对象 括号里面需要放一个对象(原型)或null
当 Object.create(null); 时 创建出来的对象就没有原型
此时就算人为的的添加原型也不管用 因为原型是系统定义好的
如
Person.prototype.name = ‘haha’;
function Person(){}
var obj = Object.create(Person.prototype);
创建出来的对象为
obj = {
proto : Person.prototype;
}
也可以
var person = new Person();
var obj = Object.create(person);