关于创建对象:
1:构造函数的方式
/** * 构造函数的方式 */ /** *构造方法 的缺点是,构造出的实例都会有一份方法(对象)。这是没必要的 */ function Person(name,age){ this.name=name; this.age=age; this.sayHello=function(){ alert(this.name); } } var p=new Person("n",1);
2:构造与原型混合的方式
/** * 构造与原型混合的方式 */ /** *构造与原型混全合的方式实现了实例共用一份方法(对象)的功能。 */ function Person(name,age){ this.name=name; this.age=age; } Persona.prototype={ sayHello:function(){ alert(this.name); } } var p1=new Person("x",1); var p2=new Person("y",2); alert(p1.sayHello===p2.sayHello);//true;
3:动态原型模式
/** * 动态原型模式 */ /** *动态原型模式将构造与原型混合的模式做了调整,组合到了一起,更优雅一些。 * @param {Object} name * @param {Object} age */ function Person(name,age){ //属性 this.name=name; this.age=age; //方法 if(typeof this.sayHello != "function"){ Person.prototype=function(){ alert(this.name); } } }
关于继承
1:原型链实现继承
/** *原型链实现继承 * 1:原型链虽然很强大,可以用它来实现继承,但它也存在一些问题。其中,最主要的问题来自包含 * 引用类型值的原型。 * 引用类型值的属性会被所有的实例共享,所以一般会将它放在构造函数中,而不是放在原型对象中。但 * 通过原型来实现继承时,原型实现上会变成另一个类型的实例。原先的实例属性也就顺理成章地变成了现在的原型属性 * 2:在创建子类型的实例时,没有办法在不影响所有对象实例的 * 情况下,给超类型的构造函数传递参数。 * 所以,实践中很少会单独使用原型链 */ function SuperType(){ this.colors=["red","blue","green"]; } function SubType(){ } SubType.prototype=new SuperType(); var s1=new SubType(); s1.colors.push("black"); //red,blue,green,black alert(s1.colors); var s2=new SubType(); alert(s2.colors);//red,blue,green,black
2:借用构造函数
/** *借用构造函数 */ /** *构造函数刚好可以解决原型链继承所面临的两个问题。但是构造函数也有缺点。 * 方法都在构造函数中定义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法, * 对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。考虑这些问题,构造函数实现继承也是很少单独使用的。 * */ function SuperType(){ this.colors=["red","blue","green"]; } function SubType(){ SuperType.call(this); } var s1=new SubType(); s1.colors.push("black"); alert(s1.colors); //"red,blue,green,black" var s2=new SubType(); alert(s2.colors); "red,blue,green";
3:组合继承
/** *组合继承 * 将原型链和借用构造函数组合到一块。使用原型链实现对原型属性和方法的继承, * 而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数利用, * 又能够保证每个实例都有它自己的属性。 * * 组合继承的缺点: * 无论什么情况下,都会调用两次超类型的构造函数:一次是在创建类型原型的时候,另一个次是在子类型的构造函数内部。 * 不仅如此,超类型的属性会在子类型和原型里同时存在,这是没有必要的。 */ function SuperType(name){ this.name=name; this.colors=["red","blue","green"]; } SuperType.prototype.sayName=function(){ alert(this.name); } function SubType(name,age){ //继承属性 SuperType.call(this,name); this.age=age; } //继承方法 SubType.prototype=new SuperType(); SubType.prototype.sayAge=function(){ alert(this.age); } var s1=new SubType("n",1); s1.colors.push("black"); alert(s1.colors);//red,blue,green,black s1.sayName(); s1.sayAge(); var s2=new SubType("Greg",2); alert(s2.colors);//red,blue,green,black s2.sayName(); s2.sayAge();
4:寄生组合式继承
/** *寄生组合式继承 * * 解决了组合继承的缺点,它只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype * 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变; */ function object(o){ function F(){} Function.prototype=o; return new F(); } function inheritPrototype(subType,superType){ var prototype=object(superType,prototype); prototype.constructor=subType; SubType.prototype=prototype; } function SuperType(name){ this.name=name; this.colors=["red","blue","green"]; } SuperType.prototype.sayName=function(){ alert(this.name); } function SubType(name,age){ SuperType.call(this,name); this.age=age; } inheritPrototype(SubType,SuperType); SubType.prototype.sayAge=function(){ alert(this.age); }
摘自《javascript 高级程序设计》
PS:关于寄生组合式继承,让我不自觉想到了甘露模型,因为太像勒。大概Nicholas C.Zakas写《javascript高级程序设计》前也像李战一样得到了观音的指点。