继承
原型链继承
<script>
function SuperType() {
this.property = true
this.color=["color",'red','blue']
}
SuperType.prototype.getSuperValue = function () {
return this.property
}
function SubType() {
this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype.getSubValue = function () {
return this.subproperty;
};
var instance = new SubType();
const supertype = new SuperType()
instance.color.push('yellow')
console.log(supertype)
console.log(instance.getSuperValue());
console.log(instance.property);
console.log(instance)
//instance指向SubType的原型,SubType的原型指向SuperType的原型,getSuperValue方 法仍然在SuperType.prototype中。但是property则位于SubType的prototype中,这是因为property是一个实例属性,而getSuperValue是一个原型方法,此时instance.constructor指向的是SuperType
//注意事项:
// 别忘记默认的原型,所有的引用类型都继承自Object,所有函数的默认原型都是Object的实例,因此默认原型里都有一个指针,指向object.prototype
// 谨慎地定义方法,给原型添加方法的代码一定要放在替换原型的语句之后,不能使用对象字面量添加原型方法,这样会重写原型链
// 原型链继承的问题
// 最主要的问题来自包含引用类型值的原型,它会被所有实例共享
// 第二个问题是,创造子类型的实例时,不能向超类型的构造函数中传递参数
</script>
借用构造函数继承
<script>
function SuperType(name) {
this.name = name
this.colors=['red','blue']
}
SuperType.prototype.getColor = function () {
return this.colors
}
function SubType() {
SuperType.call(this, '张三')
this.age = 18
}
const instancel = new SubType()
const parent = new SuperType("李四")
console.log(instancel)
console.log(parent)
//通过call或者apply方法,我们实际上是在将来新创建的SubType实例的环境下调用了SuperType构造函数。这样一来,就会在新SubType对象上执行SuperType函数中定义的所有对象初始化代码,因此,每一个SubType的实例都会有自己的对象的副本
//优势:可以传递参数
//缺点:方法都在构造函数中定义,函数无法复用。在超类型中定义的方法,子类型不可见,结果所有类型都只能使用构造函数模式。
</script>
组合继承
<script>
function Person(name,age){
this.name=name
this.age=age
this.color=["color",'red','blue']
}
Person.prototype.getName=function(){
console.log(this.name)
}
function Son(name,age,sex){
Person.call(this,name,age)
this.sex=sex
}
Son.prototype=new Person()
Son.prototype.constructor=Son
Son.prototype.getSex=function(){
console.log(this.sex)
}
const son=new Son('张三',18,"男")
console.log(son)
son.getSex()
son.getName()
//基本思想:将原型链和借用构造函数技术组合到一起。使用原型链实现对原型属性和方法的继承,用借用构造函数模式实现对实例属性的继承。这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性
//缺点:无论在什么情况下,都会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部
</script>
原型继承
<script>
// function object(o) {
// function F() {}
// F.prototype = o
// return new F()
// }
// //从本质上讲,object()对传入其中的对象执行了一次浅复制
// const person = {
// name: 'Annike',
// friendes: ['Alice', 'Joyce']
// }
// const anotherPerson = object(person)
// anotherPerson.name = "Greg"
// anotherPerson.friendes.push('Rob')
// console.log(anotherPerson)
// const yetAnotherPerson = object(person);
// yetAnotherPerson.name = 'Linda';
// yetAnotherPerson.friendes.push('Sophia');
// console.log(person.friendes);
//用处:创造两个相似的对象,但是包含引用类型的值的属性始终会共享响应的值,原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。无法传递参数
const Person={
name:'张三',
list:['aa','bb','cc','dd']
}
const son=Object.create(Person,{name:{value:'李四'}})
console.log(son)
son.list.push('ee')
console.log(Person)
</script>
寄生式继承
<script>
// 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
// }
// const Person={
// name:'张三',
// list:['aa','bb']
// }
// const son=createAnother(Person)
// console.log(son)
// son.sayHi()
// console.log(Person)
function createAnother(obj) {
const clone = Object.create(obj)
clone.getName = function () {
console.log(this.name)
}
return clone
}
const Person = {
name: '张三',
list: ['aa', 'bb']
}
const son = createAnother(Person)
son.list.push('cc')
console.log(son)
son.getName()
console.log(Person)
// 基本思想:寄生式继承是与原型式继承紧密相关的一种思路,它创造一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象,最后再返回对象。
// 缺点:使用寄生式继承来为对象添加函数,会因为做不到函数复用而降低效率,这个与构造函数模式类似,原型链继承多个实例的引用类型属性指向相同,存在篡改的可能
</script>
寄生组合式继承
<script>
// 最好的方法,最理想的方法 寄生组合式继承
// 解决了两次调用父类构造函数问题
function Person(name, age) {
this.name = name
this.age = age
this.colors = ['red', 'green']
}
Person.prototype.getName = function () {
console.log(this.name)
}
function Son(name, age, sex) {
Person.call(this, name, age) // 借用构造函数, 第一次调用父类构造函数
this.sex = sex
}
Son.prototype = Object.create(Person.prototype)
Son.prototype.constructor = Son
Son.prototype.getAge = function () {
console.log(this.age)
}
const son = new Son('张三', 18, '男')
son.colors.push('yello')
const person = new Person('李四', 25)
console.log(son)
console.log(person)
son.getAge()
son.getName()
</script>
\