day18 原型和继承

day18 原型和继承

函数的prototype

  • 每一个函数内都存在一个prototype的对象空间 构造函数也是函数,所以也存在

  • prototype这个空间会在预编译的时候进行开辟(只开辟一次)

  • prototype里面的内容可以直接通过对应的 实例对象.方法名 来访问

利用prototype可以解决构造函数会开辟多个内存空间的问题

class的相关机制

class里,constructor外部声明的函数会默认直接加入到原型prototype中

class Animal{
	constructor(){}
    say(){
        console.log('hello')
    }
}
console.log(new Animal().say === new Animal().say)//true

对象的__proto__

__ptoto__是对象的一个对象空间,他指向对应的构造函数的prototype

对象的__proto__保存着该对象的构造函数的prototype

原型链

_proto_寻找属性的过程形成的链子 被称为原型链

示例
fucntino Person(){
    
}
let person = new Person()
console.log(person.__proto__)//person构造函数的prototype
console.log(person.__proto__.__proto__)//Person构造函数的prototype(也是个对象)
理解
Object.prototype.test = function(){
    console.log('test');
}
class Animal{
    constructor(){
        this.name = 'Animal'
    }
    run(){
        console.log('run!');
    }
}
class Dog extends Animal{
    constructor(){
        super()
        this.color = 'yellow'
    }
    say(){
        console.log('wooh!');
    }
}
let dog = new Dog()
dog.age = 9
let animal = new Animal()
animal.age = 18
let obj = new Object()
obj.weight = 99

console.log(dog.__proto__)//Animal {constructor: ƒ, say: ƒ}
console.log(Dog.prototype)//Animal {constructor: ƒ, say: ƒ}
console.log(dog.__proto__.__proto__)//Animal的prototype
console.log(dog.__proto__.__proto__.__proto__)//Object的prototype
console.log(dog.__proto__.__proto__.__proto__.__proto__)//null
模拟实现instanceOf 原型链查找构造函数
function MyInstanceOf(obj,con){
    while(obj.__proto__){
        obj = obj.__proto__
        if(obj.constructor == con){
            return true
        }
    }
    return false
}
console.log(MyInstanceOf(dog,Animal));//true
模拟实现一个new
function Person(){
    this.name = name
}
function myNew(fn){
    let obj = {}//新建一个空对象
    obj.__proto__ = fn.prototype//将构造函数的原型放到这个空对象的__proto__上
    fn.call(obj)//执行构造函数,将this指向这个新对象
    return obj//最后返回这个构造完成的对象
}
console.log(myNew(Person));

继承

class继承

extends

构造函数继承
  • 原型继承

    new一个父类对象,放在子类的原型上,此后new一个子类对象,都可以继承到父类的属性和方法

    缺点:继承的属性,无法赋初始值

  • 对象冒充继承

    将父类的构造函数当做普通函数执行,并且将this指向改为子类

    缺点:无法继承原型方法

  • 组合继承

    结合原型继承和对象冒充继承

    缺点:原型上会有重复的属性

  • 寄生组合继承

    利用寄生原型(将父类原型对象加入到子类的原型上)+对象冒充

    原型上不再会有重复的属性,但是不会继承静态的属性和方法

原型继承

new一个父类对象,放在子类的原型上,此后new一个子类对象,都可以继承到父类的属性和方法

  • 缺点:继承的属性,无法赋初始值
// 原型继承
function Person(name, age) {
    this.name = name
    this.age = age
}
//原型方法
Person.prototype.sayHello = function () {
    console.log('hello')
}
//静态方法
Person.run = function () {
    console.log('run')
}
function Student(score) {
    this.score = score
}
//new一个Person对象,放在Student的原型上,此后new一个student对象,都可以继承到Person的属性和方法
Student.prototype = new Person()
console.log(new Student(99))//Student
//继承的属性,无法赋初始值,因为是个新的对象
console.log(new Student(99).name)//undefined
console.log(new Student(99).age)//undefined
new Student(99).sayHello()//hello
对象冒充继承

将父类的构造函数当做普通函数执行,并且将this指向改为子类

  • 缺点:无法继承方法
// 对象冒充继承
function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.sayHello = function () {
    console.log('hello')
}
Person.run = function () {
    console.log('run')
}
function Student(score,name,age) {
    // 将Person的构造函数当做普通函数执行,并且将this指向改为Student
    Person.call(this,name,age)
    this.score = score
}
console.log(new Student(99,'zs',18))//Student {name: 'zs', age: 18, score: 99}
new Student(99).sayHello()//报错,无法继承到Person的原型方法
组合继承

结合原型继承和对象冒充继承

  • 缺点:原型上会有重复的属性
// 寄生组合继承
function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.sayHello = function () {
    console.log('hello')
}
Person.run = function () {
    console.log('run')
}
// 结合原型继承和对象冒充继承
function Student(score, name, age) {
    // 将Person的构造函数当做普通函数执行,并且将this指向改为子类
    Person.call(this, name, age)
    this.score = score
}
// new 一个Person对象,放在Student的原型上,此后new一个student对象,都可以继承到Person的属性和方法
Student.prototype = new Person()
console.log(new Student(99,'zs',18))//Student {name: 'zs', age: 18, score: 99}
new Student(99).sayHello()//hello
寄生组合继承

利用寄生原型(将父类原型对象加入到子类的原型上)+对象冒充

  • 原型上不再会有重复的属性
  • 但是不会继承静态的属性和方法
// 寄生组合继承
function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.sayHello = function () {
    console.log('hello')
}
Person.run = function () {
    console.log('run')
}
// 结合原型继承和对象冒充继承
function Student(score, name, age) {
    // 将Person的构造函数当做普通函数执行,并且将this指向改为子类
    Person.call(this, name, age)
    this.score = score
}
// 将父类的原型对象加入到子类的原型对象
Student.prototype = Object.create(Person.prototype)
console.log(new Student(99,'zs',18))//Student {name: 'zs', age: 18, score: 99}
new Student(99).sayHello()//hello
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值