原型于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().