继承方式
原型链继承
优点:函数方法可重用
缺点:
- 引用值属性被共享
- 子类实例化时,不能向父类传递参数
function Person(name,age){
this.name = name;
this.age = age;
this.say = "说话";
this.colors = ["red","green"];
}
Person.prototype.sayName = function (){
console.log(this.say);
}
function Man (){ }
Man.prototype = new Person();
var zhangsan = new Man('zhangsan', 18);
console.log(zhangsan.name, zhangsan.age); // 无法通过子类向父类传递参数 undefined, undefined
zhangsan.sayName(); // "说话"
console.log(zhansan.color);
- 原型中包含的引用值会被所有实例间共享问题
function Person() {
this.say = "说话";
this.colors = ["red", "green"];
}
function Man() {}
Man.prototype = new Person();
let man1 = new Man();
man1.colors.push("yellow");
console.log(man1.colors); // ["red", "green", "yellow"]
let man2 = new Man();
console.log(man2.colors); // ["red", "green", "yellow"]
盗用构造继承
优点:可以传递参数
缺点:函数无法重用,所有方法都在构造函数内,每次创建对象都会创建对应的方法,大大浪费内存
function Person(name,age,sex){
this.name = name
this.age = age
this.sex = sex
this.sayName = function(){
console.log(this.name)
}
}
function Child(name,age,sex){
Person.call(this,name,age,sex)
}
let child = new Child('lisi' , 18, '男')
console.log(child) //Child { name: 'lisi', age: 18, sex: '男', sayName: [Function] }
组合继承
构造函数继承实例属性,原型链继承原型链上的属性和方法
这种方式充分利用了原型链与构造函数各自的优点,是JS中最常用的继承方法
组合模式(构造函数继承 + 原型链继承)
function Animal(name,age){
this.name = name
this.age = age
}
Animal.prototype.sayName = function () {
console.log(this.name)
}
function Cat(name,age,color){
Animal.call(this,name,age)
this.color = color;
}
Cat.prototype = new Animal(); //将Cat的原型指向Animal的原型
let cat = new Cat('xiaobai',3,'white');
console.log(cat) //Cat { name: 'xiaobai', age: 3, color: 'white' }
cat.sayName(); //xiaobai
原型式继承
本质就临时创建一个构造函数,将传入的对象赋值给这个构造函数的原型(浅克隆)
适用:不需要单独创建构造函数,但是仍然需要在对象间共享信息的场合。
缺点:引用值还是会被共享。
const person = {
name : "Nicholas",
friends: ["Shelby", "Court"]
}
const person1 = object(person);
// 方式1;
function object (o){
function F(){};
F.prototype = o;
return new F();
}
// 方式2;大写的Object
Object.create(o);
// 一样的效果
寄生式继承
和原型式继承接近,创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。
缺点:函数无法重用
function object (o){
function F(){};
F.prototype = o;
return new F();
}
function createAnother(original){
let clone = object(original); // 任何返回新对象的函数都可以。不一定要用object
clone.sayHi = function (){ };
return clone;
}
寄生组合继承
避免了组合继承的缺点,父类构造函数不会被调用两次。
父类构造器可能有很多方法和属性,创建临时的空实例代替父类传递原型,可以提高效率。
function Animal(){ }
Animal.prototype.eat = function (){ console.log("吃") }
function Cat(name) {
Animal.call(this);
this.name = name || 'Tom';
}
function object (o){
function F(){};
F.prototype = o;
return new F();
}
function inheritPrototype(SubType, SuperType){
let prototype = object(SuperType.prototype);
prototype.constructor = SubType; // 增强对象
subType.prototype = prototype; // 赋值对象
}
inheritPrototype(Cat, Animal);
let cat = new Cat();
console.log(cat.name); //Toms
cat.eat(); // "吃"
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
ES6继承
原型链继承的语法糖