ES5 中6 种方式实现继承,各自优缺点

1、原型链继承

function Father (name) {
	this.name = name
	this.hobby = ['挣钱','打小孩']
}
Father.prototype.sayName = function () {
	return this.name
}
function Son (name) {
	this.name = name
	this.age = 8
}
Son.prototype = new Father();
Son.prototype.constructor = Son;
var test1 = new Son();
test1.hobby.push('打牌')
test1.hobby // ["挣钱", "打小孩", "打牌"]
var test2 = new Son();
test2.hobby  // ["挣钱", "打小孩", "打牌"]

在创建子类型的实例时,没有办法再不影响所有对象实例的情况下,改变属性

2、构造函数继承

function Father (name) {
	this.name = name
	this.hobby = ['挣钱','打小孩']
}
Father.prototype.sayName = function () {
	return this.name
}
function Son (name) {
	Father.call(this, name)
}
var test1 = new Son('儿子')
test1.hobby.push('打牌')
test1.hobby // ["挣钱", "打小孩", "打牌"]
var test2 = new Son();
test2.hobby  // ["挣钱", "打小孩"]

优点:解决了属性值被所有实例共享的缺点
缺点:父方法里面的原型方法,对于子是不可见的

3、组合继承(原型链+构造函数)

function Father (name) {
	this.name = name
	this.hobby = ['挣钱','打小孩']
}
Father.prototype.sayName = function () {
	return this.name
}
function Son (name) {
	Father.call(this, name)
}
Son.prototype = new Father();
Son.prototype.constructor = Son;
var test1 = new Son('儿子')
test1.hobby.push('打牌')
test1.hobby // ["挣钱", "打小孩", "打牌"]
var test2 = new Son();
test2.hobby  // ["挣钱", "打小孩"]

优点:上面两个优点结合
缺点:无论是什么情况,都会调用两次父函数,一次是在创建子类原型,一次是在子类构造函数内部

4、原型式继承

function object (target) {
	function Fn () {};
	Fn.prototype = target;
	return new Fn();
}

在 object 函数内部,先传入一个临时的构造函数,然后将这个传入的对象作为整个构造函数的原型,最后返回这个临时类型的新实例,本质上是对传入的对象的浅拷贝

es5 种有个Object.create()方法 ,这个方法接受两个参数,第一个参数是作为新对象原型的的对象 和 第二个(可选)为新对象定义额外属性的对象(可以覆盖原型对象上的同名属性)
Object.create 与 上面的object 方法原理相同

var person = {
	name: 'son',
	hobbies: ['学习', '打球']
}
var person1 =  Object.create(person)
person1.name = 'person1';
person1.hobbies.push('花钱')

var person2 =  Object.create(person)
person2.name = 'person2';
person2.hobbies.push('打架')
person1.hobbies // ["学习", "打球", "花钱", "打架"]
person2.hobbies // ["学习", "打球", "花钱", "打架"]
person1.name // person1
person2.name // person2

优点:在没有必要创建构造函数,只是想让一个对象与另外一个对象保持相似的情况,原型式继承可以胜任
缺点:与原型链实现继承一样,引用类型的值会被所有实例共享

5、寄生式继承

function createAnother(original) {
	var clone = Object.create(original) // 通过调用函数创建一个新对象
	clone.sayName = function () {
		console.log(this.name);
		console.log(this.hobbies);
	}
	return clone;
}
var person = {
	name: '儿子',
	hobbies: ['打牌', '逃课']
}
var person1 = createAnother(person) 
person1.hobbies.push('花钱')
person1.sayName(); // 儿子   ["打牌", "逃课", "花钱"]
var person2 = createAnother(person)
person2.sayName(); // 儿子   ["打牌", "逃课", "花钱"]

优点:在考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的方式
缺点:同原型链继承一样,包含了引用类型的属性,会被所有实例共享

6、寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

function inheritPrototype (Son, Father) {
	var prototype = Object.create(Father.prototype); // 创建对象
	prototype.constructor = Son; // 继承原型方法
	Son.prototype = prototype;
}
function Father () {
	this.name = '爸爸'
	this.hobbies = ['喝酒']
}
Father.prototype.say = function () {
	console.log(this.name)
}
function Son () {
	Father.call(this) // 继承父类属性
	this.age = 15
}
// 继承父类原型方法
inheritPrototype (Son, Father);

Son.prototype.work= function () {
	console.log('上学')
}
Son.prototype.say = function () {
	console.log('儿子')
}
var son = new Son();
son.hobbies.push('两都有')
son.hobbies // ["喝酒", "两都有"]
son.say(); // 儿子
var father = new Father();
father.say(); //爸爸
father.hobbies // ['喝酒']

优点:与上面第 3 方法相比, 父类只在子类构造函数中调用一次,实现属性,方法继承

你可能感兴趣的:(js,基础知识)