//1、原型链继承
function father(){
this.colors = ['pink','red','yellow'];
}
father.prototype.getname = function(){
return this.colors;
}
function son(name,age){
this.name = name;
this.age = age;
}
father.prototype.songetname = function(){
return this.colors;
}
son.prototype = new father();
var base1 = new son();
base1.colors.push('blue')
console.log(base1.colors); //["pink", "red", "yellow", "blue"]
var base2 = new son();
console.log(base2.colors); //["pink", "red", "yellow", "blue"]
console.log(base2.getname()); //["pink", "red", "yellow", "blue"]
优缺分析: 1、优点 a、较构造继承来说,可以实现原型函数的共享 2、缺点 a、虽然说实现了原型函数的继承,一个实例改变了其从原型那里继承来的引用属性值时,其它继承自这个原型属性的值都将被改变。
2、构造函数继承
function father(name) {
this.name = name;
}
father.prototype.getnaem = function(){
return this.name;
}
function son(name,age){
father.call(this,name);
this.age = age;
}
var base = new son("jick",22);
console.log(base.name,base.age); // jick 22
var base2 = new son("lusi",23);
console.log(base2.name,base2.age); // lusi 23
console.log(base.getname()); //报错
1、优点 a、可以看到每个实例的属性都各自独立 2、缺点 a、但是不能继承原型的方法,----报错
总结:可以看到以上两种传统的继承方法都有缺陷,所以我们用组合继承来综合以上的两种继承方法,(原型链继承,构造函数继承)
3、组合继承
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType('Nicholas', 29);
instance1.colors.push('black');
console.log(instance1.colors); // ["red", "blue", "green", "black"]
instance1.sayName(); // Nicholas
instance1.sayAge(); // 29
var instance2 = new SubType('Greg', 27);
console.log(instance2.colors); // ["red", "blue", "green"]
instance2.sayName(); //Greg
instance2.sayAge(); // 27
1、优点 a、可以看到每个实例的属性都各自独立,原型上面的方法也都能用 2、缺点 a、我们在实现属性独立的时候不希望,原型prototype上面有太多的属性,很多余。 b、要使用此方法的话,最少要调用两次超类型的构造函数,浪费内存,影响性能。
所以还是不行,这里可以参考《JavaScript高级程序设计》里面的寄生式组合继承,将实例化继承换成浅拷贝继承就能实现。
4、原型式继承 其借用了这个函数来进行:
function object(o){
function F(){}
F.prototype = o;
return new F();
}
具体使用:
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
可以看出,效果和原型链继承差不多,都是共享属性; 然后ECMAscript5,新出了一个Objeck.create()方法,不需要再写Object()函数,直接调用就行了,具体使用如下:
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
这里Objeck.create()与Object()不同,可以传第二个参数,
var anotherPerson = Object.create(person, {
name: {
value: "Greg"
}
});
alert(anotherPerson.name); //"Greg"
5、寄生式继承 这里需要借用到object()函数,
function object(o){
function F(){}
F.prototype = o;
return new F();
}
--------------------------------------
function createAnother(original){
var clone = object(original); //通过调用函数创建一个新对象
clone.sayHi = function(){ //以某种方式来增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
-----------------------------------------------
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
这样anotherPerson就继承了person的属性,以及拥有自己的方法sayHi() 但是使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一 点与构造函数模式类似。
6、寄生组合继承 这个的话是目前公认最合适的一种继承方式,但是是在ECMAscript6之前, 需要用到函数
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
使用方式
function SuperType(name){
if( this instanceof SuperType){ //这里我用if语句来判断父构造函数的作用域是否安全,功能不受影响
this.name = name; //保证作用域安全在多人同页面开发中很有必要
this.colors = ["red", "blue", "green"];
}else{
return new SuperType;
}
}
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);
};
7、类继承
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
console.log('father 里面的this = ',this) // 这个this在16行调用的时候 为 son这个对象
}
sum() {
console.log('father 里面的sum方法: ', this.x + this.y);
}
}
// super必须在 子类的 this之前调用, 就是说必须先调用父类的构造函数
class Son extends Father {
constructor(x, y) {
super(x, y); //调用了父类中的构造函数
console.log('Son 里面的this = ',this); // 这个this在16行调用的时候 也是 son这个对象
}
say() {
super.sum() // super即可以调用父类的构造函数,也可以调用普通函数
}
}
var son = new Son(1, 2);
var son1 = new Son(11, 22);
son.sum();
son1.say();
总结,使用的时候注意共有属性和方法一定要加this使用 constructor中的this指向的是 new 出来的实例对象 自定义的方法 也指向 new出来的实例对象 ES6 中没有 变量提升, 必须向定义类, 然后才能通过类 实例化对象 子类的this对象一定要在super对象后面使用