原型模式学习之原型于in操作符、原型语法等知识点讲解
原型于in操作符
in操作符会在通过对象能够访问给定属性时返回true,无论该属性在实例中还是原型中。
function person(){ person.prototype.name='1'; person.prototype.age='3'; person.prototype.sayname=function(){ alert(this.name) } } var person1=new person(); 'name' in person1 //true 原型中 person1.name='3'; 'name' in person1 //true 实例中
for in 返回所有能通过对象返回的属性。所有开发人员定义的属性都是可以enumerable的。
for(var c in person1){ console.log(c) } vm1348:2 name vm1348:2 age vm1348:2 sayname
object.keys( )方法,接收一个对象,返回一个包含所有可枚举属性的字符串数组。
object.keys(person.prototype)//["name", "age", "sayname"] 返回一个字符串数组 object.keys(person1) //[] 通过person的实例调用方法,只返回该实例中的属性,所有返回一个空数组。
object.getownpropertynames() 方法。返回原型中所有可以枚举和不可枚举属性,该方法接收一个原型对象。
更简单的原型语法
用一个包含所有属性和方法的对象字面量来重写整个原型对象。
function person(){ } person.prototype={ name:'2', age:'3', sayname:function(){alert(this.name)} } 每次创建一个函数就会创建一个prototype对象,这个对象会自动获得constructor属性,这个属性会指向person。而person会有一个【prototype指针】, 我们重写了person.prototype,constructor不在指向person,而是指向object。可以将constructor设置为person。但是这样会造成constructor特性为true, 变成可枚举了,可以definedproperty()方法修改默认数据属性。
a的原型p的constructor指向a,而c的原型p指向c,a的原型p,用c实例化后,p被重写,a的p指向c,通过a实例化q,q的constructor指向c
继承
面向对象语言oo支持两种继承方式,接口继承和实现继承,javascript是实现继承,实现继承则继承实际的方法,实现继承主要依靠原型链来实现的。
function supertype(){ //每个函数会创建一个prototype对象,prototype对象有一个constructor属性,该属性指向supertype。 this.property=true; } //给该函数原型添加一个方法 supertype.prototype.getsupervalue=function(){ return this.property; } //创建一个新函数 function subtype(){ this.subproperty=false; } //继承 subtype.prototype=new supertype(); subtype的原型继承了supertype。也就subtype的原型是supertype的实例。 //给subtype的原型添加一个方法 subtype.prototype.getsubvalue=function(){ return this.subproperty; } var instance=new subtype()// 实例化一个对象 instance.getsupervalue //treun 先搜索实例有没有这个属性,然后搜索subtype原型,之后搜索supertype原型。 注意!给subtype原型添加方法,要在subtype实例原型替换后添加,如果在原型没有替换之前添加方法,给方法将别移除,因为替换的时候重写了prototype。 可以说instance是subtype supertype object的实例。 subtype的原型prototype指向supertype的原型,supertype的prototype指向object。本来subtype的原型constructor指向subtype,因为supertype实例化了subtype的原型,constructor也被重写,指向了supertype。
原型模式多用于定义方法和共享属性,构造函数多用于定义实例属性。
借用构造函数
在子类型构造函数调用超类类型构造函数,使用apply()和call()方法可以在新创建的对象上执行构造函数。
function supertype(){ this.colors=['blue','gray','red']; }
function subtype(name){
supertype.call(this); //子类型继承超类型属性 this.name='ma' }
var instance=new subtype();var instance.colors.push('pink') // length 4 var instance1=new subtype();instance1.colors.length //3 子类型共享超类型属性,但是实例不能共享同一个对象的实例。也就子类型看不到超类型原型中定义的方法,结果就是所有类型只能使用构造函数模式。借用构造函数有一个很大的优势,是可以对超类型传递参数。function supertype(name){
this.name=name;
}function subtype(name){
supertype.call(this,name); //call()为超类型传递参数
}var instance=new suptype('cai');instance.name //cai 为了确保超类型构造函数不会重写子类型,请在调用超类型后再为子类型添加属性。
组合继承
组合继承有时候也叫做伪经典继承,将原型链和借用构造函数的技术合到一块,使用原型链实现对原型属性和方法的继承,借用构造函数来实现对实例属性的继承。
function supertype(name){ this.name=name; this.colors=['red','yellow','gray']; } supertype.prototype.getsupervalue=function(){ alert(this.name); } function subtype(name){ 构造函数在调用超类,传入name参数(子类拥有了超类属性),之后要定义了自己属性age。 supertype.call(this,name); this.age='23'; } //借用构造函数 subtype.prototype=new supertype() //原型替换,sub的原型被重写,重写后拥有super的属性及原型方法。sub的原型变成了super的实例。 subtype.prototype.constructor=subtype //增强对象,弥补因重写原型而失去的默认constructor属性。 subtype.prototype.sayname=function(){ alert(this.age) } var instance1=new subtype('cai'); instance1.colors.push('blue'); instance1.colors.length //4 var instance2=new subtype('ma'); instance2.getsupervalue(); //ma 这样就让两个不同的super实例拥有自己的属性。instanceof也可以识别它们基于组合继承创建对象
原型试继承
function object(o){ //每次给原型添加属性,要么实例化,要么prototype.添加。 function f(){} //通过这个函数,我们直接将对象传入该函数,会返回一个临时实例,实例原型就是我们传入的对象。把不变的东西封装起来。 f.prototype=o; return new f(); } var person={name:'cai',colors:['red','green','blud']}; var person1=object(person); person1.name //cai 要求你必须有一个对象可以作为另一个对象的基础,将person作为另一个对象的基础,传入object。返回一个新对象,person作为新对象的原型。 ecmascript 5 object.create()方法规范了原型式继承。这个方法接收两个参数:一个是作为新对象原型的对象和(可选)一个新对象定义额外属性的对象。
var person={name:'cai', colors:['red','green','blud']}; var create1=object.create(person); create.name //cai object.create()的第二个参数与object.definedproperties()第二个参数格式相同。 var create2=object.create(person,{name:{value:22}}); create2.name //22
寄生式继承
寄生继承的思路,创建一个仅用于封装继承过程的函数,该函数在内部已某种方式来增强对象。
function createanother(o){ var clone=object(o); clone.sayname=function(){ alert(hi); } return clone; }
var person={name:'cai',colors:['red','green','blud']};var instance1=createanother(person) 返回一个新对象,不仅具有person的方法也有自己的方法sayname
寄生组合继承
function supertype(name){ this.name=name; this.colors=['blue','green','gray']; } function subtype(name){ supertype.call(this,name); //第二次调用super this.age=22; } subtype.prototype=new supertype(); //第一次调用super 组合继承的缺点就是调用了两次超类型,而寄生组合继承解决了这个问题 function inheritproperty(subtype,supertype){ var prototype=object(supertype.prototype); //传入supertype原型,返回一个新对象prototype prototype.constructor=subtype; subtype.prototype=prototype; //重写subtype原型,指定对象 }
function subtype(name){ supertype.call(this,name); this.age=22; }
inheritproperty(subtype,supertype); 通过寄生组合继承,只调用了一次supertype().
下一篇: 让自己快速脱单的四条绿色通道