【js中的继承】继承的相关知识以及学习笔记

目录


继承

继承的概念:子承父业,儿子继承了爹里面的内容,那么爹所拥有的属性和方法,子类经过继承之后同样自动拥有

原生js的继承的方法有:构造函数继承原型链继承混合构造原型链继承混合构造寄生式继承(完美继承)ES6继承


构造函数继承

继承方式:父类在构造函数中通过this,创建了实例属性和实例方法,子类在继承的时候需要在子类的构造函数中改变父类的this指向,就可以实现继承父类.call(this,name,age)

缺点:相同的方法,每创建一个对象,就会开辟一个新的内存空间,所以造成大量的内存浪费。也就是说,在实用同一个构造函数new出来的对象 他们不在同一个内存空间里

代码:

//ES5的构造函数
//Dog
function Dog(name,age){
    //实例属性
    this.name = name;
    this.age = age;
    //实例方法
    this.showName = function(){
        return this.name;
    }
    this.showAge = function(){
        return this.age;
    }
}
//父类中的this代表:new Dog后的实例对象。
//子类(哈士奇) 继承过程
function Huskie(name,age){
    Dog.call(this,name,age); //this : new Huskie后的实例对象
    // Dog.apply(this,[name,age]); 修改this指向的三个方法 bind方法穿回来是一个函数,不调用就不会执行,所以要在后面加上()
    // Dog.bind(this,name,age)();
}
//创建一个子类对象
let hsk = new Huskie('二哈',3);
console.log(hsk.showName());//二哈 成功继承了父类的方法showName

原型链继承

原型的特点:写在原型对象中的属性或方法都共同享有一个空间

继承方式:先创建一个子类的构造函数,然后通过函数名prototype找到原型对象 = new 继承的父对象;想要修改自己的属性或方法要在继承了父类之后再修改

原型及原型链:(面试题)

  1. 每一个函数都有一个属性prototype,通过这个属性就可找到该函数对应的原型对象
  2. 每一个对象都有一个属性__proto__,通过这个属性就可以找到该对象的原型对象。原型对象也属于对象,也有__proto__,通过这个属性又可以找到当前原型对象父级原型对象,以此类推,这样一直向上查找的过程就叫做原型链。最终找到的是null对象。
  3. 每一个原型对象都有一个属性constructor,这个属性可以找到原型对象的构造函数。(反着找)

原型链继承的缺点:所有的对象都共享同样的属性,比如所父亲叫小花,那么继承的所有子类都会叫小花。

代码:

 //Cat 原型链继承
function Cat(){} //构造函数
//原型属性
Cat.prototype.name = '小花'; //这里通过函数的属性prototype找到原型对象设置name属性
Cat.prototype.age = 3;//与上面同理
//原型方法
Cat.prototype.showName = function(){
    return this.name;//原型方法的设置语法
}
Cat.prototype.showAge = function(){
    return this.age;
}

let cat_01 = new Cat();
let cat_02 = new Cat();
console.log(cat_01.showName === cat_02.showName); //true 这里的方法共同享有一个空间

//原型链继承方法
function Garfield(){} //构造函数
//创建一个父类的对象赋值给子类的原型对象
Garfield.prototype = new Cat();
//自己的属性或方法要写在继承父类之后
Garfield.prototype.sex = '公';
let gf = new Garfield();
console.log(gf.showName());//小花  继承了父类的名字和方法

混合构造原型链继承

继承方式:为了解决原型链继继承的弊端,子类在继承的时候,通过构造函数继承父类的属性,通过原型链继承父类的方法

缺点:调用了两次父类构造函数,生成了两份实例对象。

代码:

//混合继承  构造函数继承属性 原型链继承方法
function Pig(name,age){
    //实例属性
    this.name = name;
    this.age = age;
}
//原型方法 
Pig.prototype.showName = function(){
    return this.name;
}

//子类
function Ericius(name,age){
    Pig.apply(this,[name,age]); //构造函数继承属性 修改this指向
}
//原型链继承方法
Ericius.prototype = new Pig();

let hz = new Ericius('天蓬元帅',888);
console.log(hz.showName());//天蓬元帅 成功继承

混合构造寄生式继承

完美的继承方式

继承方法:构造函数继承属性寄生式继承继承方法

为什么说寄生式继承方式完美?:因为此方法在原型对象里面就已经继承完毕了。

寄生式继承的方法:使用for(let key in 父类的原型对象)遍历父类的原型对象,赋值给子类的原型对象

// 混合构造寄生式继承
function Dog(name,age){
    this.name = name;
    this.age = age;
}
Dog.prototype.showName = function(){
    return this.name;
}

function Tibetan(name,age){
    //构造函数继承
    Dog.call(this,name,age);
}
// Tibetan.prototype = Dog.prototype;
// //寄生式继承
for(let key in Dog.prototype){
    Tibetan.prototype[key] = Dog.prototype[key];
}
let tib = new Tibetan('獒哥',18);
console.log(tib.showName());

ES6继承

继承方式:通过class 子类 extends 父类的语法继承、在constructor中使用super()方法继承父类的属性,父类的原型方法会自动继承

代码:

class Dog{
    constructor(name,age){
        //实例属性
        this.name = name;
        this.age = age;
        //实例方法
    }
    //原型方法
    showName(){
        return this.name;
    }
}

class Huskie extends Dog{
    constructor(name,age){
        super(name,age);
    }
}
let hsk = new Huskie('二哈',3);
console.log(hsk.showName());

扩展

就近原则

new 一个实例对象时,会找最近的属性赋值。设置>构造函数>构造函数的原型对象。

代码:

案例一:

function Person(name){
    //实例属性
    this.name = name;
}
// 原型属性
Person.prototype.name = '王五';
// 原型方法
Person.prototype.showName = function(){
    return this.name;
}
let ps = new Person('李四');
ps.name = '张三';
console.log(ps.showName());//张三
/*
    分析:根据就近原则,直接设置了对象的属性name,最近一次是将张三赋值
    给ps的name属性 所以输出张三
*/ 

案例二:

function Person(name){
    //实例属性
    this.name = name;
}
// 原型属性
Person.prototype.name = '王五';
// 原型方法
Person.prototype.showName = function(){
    return this.name;
}
let ps = new Person('李四');
console.log(ps.showName());//李四
/*
    分析:根据就近原则,没有设置实例对象的属性name,找到最近一次赋值是构造函数中的实例属性,所以输出李四。
*/

案例三:

function Person(name){
    //实例属性
}
// 原型属性
Person.prototype.name = '王五';
// 原型方法
Person.prototype.showName = function(){
    return this.name;
}
let ps = new Person('李四');
console.log(ps.showName()); //王五
/*
    分析:没有设置实例对象的属性name,构造函数中没有实例属性,原型对象
    中有原型属性,所以输出王五。
*/ 

修改js中原有对象的方法

增加方法

如果在现有的方法中无法满足需求,可以通过对象.prototype.新增的方法来给这个对象增一个方法。

语法代码:

//Array
// 给数组新增一个求和的方法
Array.prototype.fnSum = function(){
    return this.reduce((a,b) => {
        return a + b;
    })
}
// 给数组新增求最大值的方法
Array.prototype.fnMax = function(){
    return Math.max.apply(null,this);
}
let arr = [1,2,3,4,5];
let sum = arr.fnSum();
let max = arr.fnMax();
console.log(sum,max);

// 同样可以对 String、Date 进行增加方法

删除属性

通过 delete 对象.属性可以删除该属性。

语法代码:

function Dog(name){
    this.name = name;
}
let dog = new Dog('小黄');
//delete : 删除对象中指定的属性
delete dog.name;
console.log(dog.name);//undefined

检测一个属性是否属于某个对象

通过'属性名' in 对象来检测

语法代码:

function Dog(name){
    this.name = name;
}
let dog = new Dog('小黄');
//in  : 检测一个属性是否属于某个对象
if('age' in dog){
    alert(true);
}else{
    alert(false);
}
// 输出false 因为dog 这个对象没有age这个属性

总结

继承

js原生的继承方式有:构造函数继承原型链继承混合构造原型链继承混合构造寄生式继承(完美继承)ES6继承

原型及原型链:

  1. 每一个函数都有一个属性prototype,通过这个属性就可找到该函数对应的原型对象
  2. 每一个对象都有一个属性__proto__,通过这个属性就可以找到该对象的原型对象。原型对象也属于对象,也有__proto__,通过这个属性又可以找到当前原型对象父级原型对象,以此类推,这样一直向上查找的过程就叫做原型链。最终找到的是null对象。
  3. 每一个原型对象都有一个属性constructor,这个属性可以找到原型对象的构造函数。(反着找)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值