1)原型继承
let Person = { eays: 2, head: 1 } function Woman(){ } Woman.prototype = Person Woman.prototype.constructor = Woman //由于给prototype重新赋值,需要让constructor重新指回原来的构造函数 let one = new Woman console.log(one); console.log(one.eays);//2 继承了Person function Man(){ } Man.prototype = Person let two = new Man console.log(two.head);//1 继承了Person
问题:我们给Woman添加方法,Man也会添加上
let Person = {
eays: 2,
head: 1
}
function Woman(){
}
Woman.prototype = Person
Woman.prototype.constructor = Woman //由于给prototype重新赋值,需要让constructor重新指回原来的构造函数
Woman.prototype.boby = function(){
console.log('宝贝');
}
let one = new Woman
console.log(one);
// console.log(one.eays);//2 继承了Person
function Man(){
}
Man.prototype = Person
let two = new Man
console.log(two);
// console.log(two.head);//1 继承了Person
原因:他们原型都继承了Person,接收了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就都会影响
解决方法:利用构造函数 (以下几种方法使用同一个例子(Person))
function Person(){ this.eays = 2 this.head = 1 } function Woman(){ } Woman.prototype = new Person() //每次new出来一个新的对象,结构一样,内容一样,对象不一样,就实现了更改一个而不影响另一个 Woman.prototype.constructor = Woman //由于给prototype重新赋值,需要让constructor重新指回原来的构造函数 Woman.prototype.boby = function(){ console.log('宝贝'); } let one = new Woman console.log(one); // console.log(one.eays);//2 继承了Person function Man(){ } Man.prototype = new Person() //同理 Man.prototype.constructor = Man let two = new Man console.log(two); // console.log(two.head);//1 继承了Person
2)call、apply继承
function Person(eays,head){ this.eays = eays this.head = head this.Play = function(){ console.log('玩'); } } Person.prototype.eat = function () { console.log('麻辣烫'); } function Student(eays,head,sex){ //cal() 改变this指向,实现继承 Person.call(this,eays,head,sex) // Person.apply(this,[eays,head,sex]) this.sex = sex } Student.prototype.study = function(){ console.log('学习'); } let stu1 = new Student(2,1,'女') console.log(stu1); console.log(stu1.eays); //2 console.log(stu1.sex); //女 stu1.study() //学习 stu1.eat() //报错
call,apply继承【只能继承所有构造的属性和方法,不能继承原型的内容】
3)实例继承
function Person(eays,head){ this.eays = eays this.head = head this.Play = function(){ console.log('玩'); } } Person.prototype.eat = function () { console.log('麻辣烫'); } function Student(eays,head,sex){ let stu2 = new Person(eays,head) stu2.sex = sex return stu2 } Student.prototype.study = function(){ console.log('学习'); } let stu1 = new Student(2,1,'女') console.log(stu1); console.log(stu1.eays); //2 console.log(stu1.sex); //女 stu1.eat() //麻辣烫 stu1.study() //报错,不能往Student原型上添加内容
由于return,当new Student(2,1,'女')的时候实际拿到的是Person,这样我们虽然可以用Person原型上的内容但是我们Student原型上的内容却不能用了,也就不能在往Student原型上添加内容了
4)拷贝继承
function Person(eays,head){ this.eays = eays this.head = head this.Play = function(){ console.log('玩'); } } Person.prototype.eat = function () { console.log('麻辣烫'); } //拷贝继承 function Student(eays,head,sex){ let stu2 = new Person(eays,head) for( k in stu2){ // console.log(stu2[k]); //遍历出来的东西添加到原型身上 Student.prototype[k] = stu2[k] } this.sex = sex } Student.prototype.study = function(){ console.log('学习'); } let stu1 = new Student(2,1,'女') console.log(stu1); console.log(stu1.eays); //2 console.log(stu1.sex); //女 stu1.eat() //麻辣烫 stu1.study() //学习
和上面的方法类似,只不过弥补了上面的不足,利用拷贝继承,new Student(2,1,'女')的时候拿到的将是我们new出来的构造函数本身,也可以实现往Student原型上添加内容了
5)组合继承
用构造继承方法(call)继承父级的普通属性和方法;
用原型继承,继承父级的原型属性和方法
重点:结合了两种模式的优点,传参和复用。
特点: 1、可以继承父类原型上的属性,可以传参,可复用; 2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
function Person(eays,head){ this.eays = eays this.head = head this.Play = function(){ console.log('玩'); } } Person.prototype.eat = function () { console.log('麻辣烫'); } //组合继承 function Student(eays,head,sex){ Person.call(this,eays,head) this.sex = sex this.study = function(){ console.log('学习'); } } Student.prototype = new Person() let stu1 = new Student(2,1,'女') console.log(stu1); console.log(stu1.eays); //2 stu1.study() //学习 stu1.eat() //麻辣烫
6)寄生继承
1, 融合了以上所有方式的优点 2, 实现复杂
function Person(eays,head){ this.eays = eays this.head = head this.Play = function(){ console.log('玩'); } } Person.prototype.eat = function () { console.log('麻辣烫'); } //寄生继承 function Student(eays,head,sex){ Person.call(this,eays,head) this.sex = sex this.study = function(){ console.log('学习'); } } (function (){ let Super = function(){ } Super.prototype = Person.prototype Student.prototype = new Super() })() let stu1 = new Student(2,1,'女') console.log(stu1); console.log(stu1.eays); //2 console.log(stu1.sex); //女 stu1.eat() //麻辣烫
和上面相对比,原型里面干干净净只有原型里面的东西,构造里面只有构造的内容
ES6中继承
class User{ constructor (name,age){ this.name = name; this.age = age; } showName(){ console.log(`my name is ${this.name}`); } showPass(){ console.log(`my age is ${this.age}`); } } class Vip extends User{ constructor(name,age,stuid){ super(name,age) this.stuid = stuid } study(){ console.log(this.name + '学习'); } } let vip = new Vip('jack',20,1001) console.log(vip); vip.showPass() vip.study();
小案例
<body>
<input type="color" id="color">
<input type="button" id="btn" value="提交">
<script>
btn.onclick = function(){
var val = color.value;
val.getRGB();
}
String.prototype.getRGB = function(){
let color1 = this.replace(/#/g,'')
let a = parseInt(color1.substring(0,2),16);
let b = parseInt(color1.substring(2,4),16);
let c = parseInt(color1.substring(4),16);
let rgb = `rgb(${a},${b},${c})`
console.log(rgb);
}
</script>
</body>