继承的3种优缺点
new执行过程
const person = new Person(args);
//相当于
const person = Person.new(args);
Function.prototype.new = function(){
let obj = new Object();
obj.__proto__ = this.prototype;
const ret = this.apply(obj, arguments);
return (typeof ret == 'object' && ret) || obj;
}
- 原型链继承
// (1) 父类
function Persion(name,age){
this.name = name;
this.age = age;
}
// 父类的原型对象属性
Persion.prototype.id = 10;
// 子类
function Boy(sex){
this.sex = sex;
}
// 继承实现
Boy.prototype = new Persion('c5',27);
var b = new Boy();
alert(b.name)// c5
alert(b.id)//10
// (2) 父类
function Parent(age) {
this.name = ['2','4'];
this.age = age;
}
// 父类的原型对象属性
Parent.prototype.getName = function(){
return this.name
};
// 子类
function Child(sex) {
}
Child.prototype = new Parent(23)
var child = new Child();
child.name.push('6');
console.log(child.name);//["2", "4", "6"]
console.log(child.getName());//["2", "4", "6"]
var child2 = new Child();
console.log(child2.name);//["2", "4", "6"]
优点:既继承了父类的模板,又继承了父类的原型对象。优点是继承了父类的模板,又继承了父类的原型对象,缺点就是父类实例传参,不是子类实例化传参,不符合常规语言的写法,而且引用类型的属性被所有实例共享(2)。
- 类继承(继承父类构造函数,但不继承父类的原型)避免了引用类型[m]的属性被所有属性共享;可以在Child向Parent传参。[经典继承] 缺点:方法只能在构造函数中定义,每次创建实例都会开辟空间给方法。
function Parent(name, age) {
this.name = name;
this.age = age;
this.m=["ghg",'ghjg','fghf']
}
// 父类的原型对象属性
Parent.prototype.getName = function () {
return this.name
};
// 子类
function Child(sex,name,age) {
Parent.call(this, name, age)
this.sex = sex;
}
var child = new Child('女','xx',22);
child.m.push('bhjb')
// console.log(child.getName());// Uncaught TypeError: child.getName is not a function
console.log(`性别:${child.sex} 姓名:${child.name} 年龄:${child.age}`);
console.log(child.m);// ["ghg", "ghjg", "fghf", "bhjb"]
// 性别:女 姓名:xx 年龄:22
var child2 = new Child('女', 'xx', 22);
// console.log(child.getName());// Uncaught TypeError: child.getName is not a function
console.log(`性别:${child2.sex} 姓名:${child2.name} 年龄:${child2.age}`);
// 性别:女 姓名:xx 年龄:22
console.log(child2.m);// ["ghg", "ghjg", "fghf"]
- 组合继承(原型链和经典) 解决引用属性实例共享和不能继承父类原型链上的属性;缺点:两次调用Parent构造函数
function Parent(name) {
this.name = name;
this.m=["ghg",'ghjg','fghf']
}
// 父类的原型对象属性
Parent.prototype.getName = function () {
return this.name
};
// 子类
function Child(sex,name) {
Parent.call(this, name)
this.sex = sex;
}
Child.prototype=new Parent()
var child = new Child('女','xx');
child.m.push('bhjb')
console.log(child.getName());// xx
console.log(`性别:${child.sex} 姓名:${child.name} `);
console.log(child.m);// ["ghg", "ghjg", "fghf", "bhjb"]
// 性别:女 姓名:xx 年龄:22
var child2 = new Child('女', 'xx');
console.log(`性别:${child2.sex} 姓名:${child2.name} `);
// 性别:undefined 姓名:xx 年龄:22
console.log(child2.m);// ["ghg", "ghjg", "fghf"]
- 后面再补组合继承
- ES6 class
// class 实现类的继承
class Parent{
// 相当于构造函数
constructor(name){
this.name=name;
}
// 相当于原型
sayName(){
console.log(this.name);
}
}
class Child extends Parent{
// 相当于构造函数
constructor(childName,age) {
// super相当于 把类的原型拿过来
// 以及Parent.call(this, childName)
super(childName);
this.age = age;
}
// 相当于原型
getAge() {
console.log(this.age);
}
}
let a = new Child('daisy',24)
a.sayName(); //汪某
a.getAge(); // 24
// ES6 里面的class
/**注意两点:
* 1. 在类中声明方法的时候,千万不要给方法加上function关键字
* 2. 方法之间不用,;等任何符号
* box.hasOwnProperty('nums')指实例上的属性,但是'nums' in box 表示在原型或者实例上能找到
*
*/
//ES6中 class 不存在变量提升
class Parent {
constructor({name, age}){
this.name=name;
this.age=age;
}
say(){
console.log(this.sex);
}
}
class child extends Parent{
constructor({name, age,sex}) {
// super 把类的原型 以及父对象中的this继承
super({name,age});
this.sex=sex
}
getAge(){
console.log(this.age);
}
}
var child1 = new child({name:'st',age:24,sex:'女'})
console.log(child1.name, child1.age, child1.sex); //st 24 女
child1.say();//女
child1.getAge(); //24