<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 值类型(基本类型):字符串(string)、数值(number)、布尔值(boolean)、undefined、null
// 引用类型:对象(Object)、数组(Array)、函数(Function)
/*
原型链 继承
问题:1.包含引用类型值的原型属性会被所有实例共享 数组(引用类型值)。
2.在创建子类型的实例时,不能向超类型的构造函数中传递参数。
*/
function SuperType() {
this.property = true;
// this.colors = ["red","black"];
}
SuperType.prototype.colors = ["red", "black"];
SuperType.prototype.getSuperValue = function () {
return this.property;
};
function SubType() {
this.subproperty = false;
}
//继承了SuperType 原型链继承
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
return this.subproperty;
};
var instance1 = new SubType();
var instance2 = new SubType();
instance1.colors.push("green");
console.log(instance1.getSuperValue()); //true
console.log(instance1.colors);// ["red", "black", "green"]
console.log(instance2.colors);// ["red", "black", "green"]
console.log(instance1);// SubType {subproperty: false}
console.log(instance1.__proto__);// SuperType {property: true, getSubValue: ƒ}
/*
借用构造函数 继承 候也叫做 伪造对象 或 经典继承
问题:方法都在构造函数中定义,因此函数复用就无从谈起了
*/
function SuperType2(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
this.sayName = function () {
console.log(this.name);
}
}
function SubType2() {
//继承了SuperType 构造继承
// this -> SubType
// SuperType2.call(this);
// 传递参数
SuperType2.call(this, "赵品霖");
}
//继承了SuperType
// SubType.prototype = new SuperType();
var instance3 = new SubType2();
var instance4 = new SubType2();
instance3.colors.push("black");
console.log(instance3.colors); // ["red", "blue", "green", "black"]
console.log(instance4.colors); //["red", "blue", "green"]
console.log(instance3.sayName == instance4.sayName); //false 函数无法复用
console.log(instance3);//SubType2 {name: "赵品霖", colors: Array(4), sayName: ƒ}
console.log(instance3.__proto__);//{constructor: ƒ}
/*
组合继承
思想:即在子类型构造函数的内部调用超类型构造函数
instanceof 和isPrototypeOf()也能够用于识别基于组合继承创建的对象。
问题:无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
解决方法 ——寄生组合式继承。
*/
function SuperType3(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType3.prototype.sayName = function () {
console.log(this.name);
}
function SubType3(name, age) {
//继承属性 构造继承
SuperType3.call(this, name);////第二次调用SuperType()
this.age = age;
}
//继承方法 原链继承
SubType3.prototype = new SuperType3();////第一次调用SuperType()
SubType3.prototype.constructor = SubType3;
SubType3.prototype.sayAge = function () {
console.log(this.age);
};
// 实例既分别拥有自己属性——包括colors 属性,又可以使用相同的方法了。
var instance5 = new SubType3("aa", 20);
var instance6 = new SubType3("bb", 21);
instance5.colors.push("black");
console.log(instance5.colors); // ["red", "blue", "green", "black"]
console.log(instance6.colors); //["red", "blue", "green"]
instance5.sayName();//aa
instance6.sayName();//bb
console.log(instance5.sayName == instance6.sayName); //true
console.log(instance5); //SubType3 {name: "aa", colors: Array(4), age: 20}
console.log(instance5.__proto__); //SuperType3 {name: undefined, colors: Array(3), constructor: ƒ, sayAge: ƒ}
/*
原型式继承
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
Object.create(person);
在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以胜任的。
不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。
*/
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
// ECMAScript 5 通过新增Object.create()方法规范化了原型式继承。
// 这个方法接收两个参数:一个用作新对象原型的对象和(可选的); 一个为新对象定义额外属性的对象
var anotherPerson = Object.create(person);
// 重写name
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
// var yetAnotherPerson = Object.create(person);
// yetAnotherPerson.name = "Linda";
// Object.create() 接受第2个参数
var yetAnotherPerson = Object.create(person, {
name: {
value: "Linda"
}
});
yetAnotherPerson.friends.push("Barbie");
console.log(person.friends); //["Shelby", "Court", "Van", "Rob", "Barbie"]
/*
寄生式继承:
寄生式继承的思路与寄生构造函数和工厂模式类似.
即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。前
*/
function createAnother(original) {
var clone = Object(original); //通过调用函数创建一个新对象
clone.sayHi = function () { //以某种方式来增强这个对象
console.log("hi");
};
return clone; //返回这个对象
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
/*
寄生组合式继承
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法.
基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。
本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
它只调用了一次SuperType 构造函数,并且因此避免了在SubType.prototype 上面创建不必要的、多余的属性。
与此同时,原型链还能保持不变;因此,还能够正常使用instanceof 和isPrototypeOf()。
开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
*/
function inheritPrototype(subType, superType) {
var prototype = Object(superType.prototype); //创建对象 寄生式继承来继承超类型的原型
// 弥补因重写原型而失去的默认的constructor 属性
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象 将结果指定给子类型的原型。
}
function SuperType4(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType4.prototype.sayName = function () {
console.log(this.name);
};
function SubType4(name, age) {
SuperType4.call(this, name);
this.age = age;
}
inheritPrototype(SubType4, SuperType4);
SubType4.prototype.sayAge = function () {
console.log(this.age);
};
var instance7 = new SubType4("ee", 19);
var instance8 = new SubType4("ff", 22);
instance7.colors.push("black");
console.log(instance7.colors);// ["red", "blue", "green", "black"]
console.log(instance8.colors);// ["red", "blue", "green"]
console.log(instance7.sayName == instance8.sayName);// true
console.log(instance7.sayAge == instance8.sayAge);// true
</script>
</body>
</html>