学习js的几种继承方式
文章旨在梳理JavaScript中几种继承方式
一、原型链继承
//父类
var Person = function(name,age){
this.name = name;
this.age = age;
}
//在父类上添加方法,子类可以继承该方法
Person.prototype.getName = function(){
console.log(this.name);
}
Person.prototype.getSex = function(){
console.log(this.sex);
}
//子类
var Child = function(name,sex){
this.name = name;
this.sex = sex;
}
// 报错:子类不可直接在prototype上添加属性和方法,因为会影响父类的原型
// Child.prototype.getSex = function(){
// console.log(this.sex);
// }
//继承,让Child继承Person的方法
Child.prototype = new Person();
//将Child实例的Constructor指向自己的构造函数Child
Child.prototype.constructor = Child;
//因为此模式会共享属性和方法,所以当一个实例修改属性和方法时会影响其他实例,而且子类型无法向超类型传递参数(可以通过call传递,得出改进方法组合继承)。
var person1 = new Child('Alice');
console.log(person1.constructor);//[Function: Child]
person1.getName();//继承了Person的方法
person1.age = 18;//继承了Person的属性
console.log(person1);//Child { name: 'Alice', sex: 'female', age: 18 },继承了Person的属性并且保留自己的属性
- 缺点:
(1)修改一个实例可能会影响其他实例,因为当你修改一个实例的属性和方法时,可能是直接在原型上修改的,因此其他继承次原型的实例也可能被修改:
//当一个实例修改属性和方法时会影响其他实例
function person () {}
person.prototype = {
constructor: Person,
name: 'xu',
age: ['1', '2'],
sex: '男',
showAge: function () {
console.log(this.age);
}
}
var person1 = new person();
var person2 = new person();
person1.age.push('3');
//是对属性的引用,那么你对它操作的时候,实际上就是对原型上操作。但是
console.log(person1.age, person2.age); // ['1', '2', '3'] , ['1', '2', '3']
person1.age = ['1'];
//这就不同了,相当于给person1这个对象实例添加了一个属性,不是给原型添加。关键在于等于。
console.log(person1.age, person2.age); // ['1'] , ['1', '2', '3']
扩展:
Vue中的组件的data 为什么是一个函数?
https://blog.csdn.net/weixin_42554191/article/details/109702420
防止修改实例时影响其他实例。
(2)子类无法向父类传递参数(改进方法:和call一起组合继承)
二、修改this的指向来继承(call,apply,bind)
//利用call继承(相关知识点:函数参数传递)
function Animal(name,age){
this.name = name;
this.age = age;
console.log(arguments);//arguments是子类向父类传递的参数
this.arg = Array.prototype.slice.call(arguments,0);
this.getName = () =>{
console.log(this.name);
}
this.getOtherInfo = (key) =>{
if(this.name === key){
console.log(this.age);
}
if(this.age === key){
console.log(this.name);
}
}
}
function bird(){
var arg = Array.prototype.slice.call(arguments,0);
console.log(arg);
Animal.call(this,arg);//可以通过这个向父类传递参数
}
var b1 = new bird(1,2,3);
b1.age = 18;//继承了父类的属性
b1.name = 'AA'//继承了父类的属性
console.log(b1);
// 输出:
// bird {
// name: 'AA',
// age: 18,
// arg: [ [ 1, 2, 3 ] ],
// getName: [Function (anonymous)],
// getOtherInfo: [Function (anonymous)]
// }
b1.getName();//AA,继承了父类的方法
b1.getOtherInfo('AA')//18
- 缺点:
函数无法复用(为什么无法复用,有知道的大神可以在评论区告诉我一下吗?)
三、组合继承
结合一、二两种继承(推荐)
function parent(name) {
this.name = name
}
parent.prototype.sayName = () => {
alert(this.name)
}
function child(name, age) {
parent.call(this, name)//通过此可以将子类参数传递给父类
this.age = age
}
child.prototype = new parent()
child.prototype.constructor = child
child.prototype.sayAge = () => {
alert(this.age)
}
参考:
Vue中的组件的data 为什么是一个函数?
https://blog.csdn.net/weixin_42554191/article/details/109702420
原型链实现继承的6种方式:
https://blog.csdn.net/weixin_33750452/article/details/91453468?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-4&spm=1001.2101.3001.4242
什么是原型、原型链、继承?
https://blog.csdn.net/xiao___fang/article/details/90450711