原型与继承

    原型 --- 原型对象
      - 当函数定义创建的时候,系统自动创建分配的一个对象
      1. 原型和函数的关系
        + 函数都有一个属性 prototype ,这个属性指向了 对应的原型对象
        + 原型对象都有一个constructor属性,指向 对应的构造函数
      2. 函数和实例对象的关系
        + 实例对象是 构造函数通过new 语法创建的
      3. 实例对象和原型的关系
        + 对象都有一个属性 __proto__,这个属性指向 创建该实例对象的构造函数对应的原型对象
        + 对象可以直接访问到原型中的属性和方法
      注意: 
        1. 实例对象的__proto__指向原型对象,这个__proto__是一个非标准属性,如果我们要操作原型对象的时候,都是通过构造函数.prototype 来直接操作原型对象
        2. 我们给原型对象添加的属性和方法,都是给实例对象使用的
        3. 需要给实例对象添加的方法,我们一般不会在构造函数内直接给实例对象添加方法,而是将方法写入对应的原型对象中
  
// 自定义 Person 构造函数
function Person(name) {
    this.name = name
}
// 给原型对象添加属性方法
Person.prototype.age = 18;
Person.prototype.say = function() {
    console.log('hi')
}

// 原型对象
// console.log( Person.prototype )
// 原型对象的constructor指向 构造函数
// console.log( Person.prototype.constructor === Person) // true
// 实例化对象
let p1 = new Person('zf');
// 实例对象 的__proto__ 指向对应的原型对象
// console.log( p1.__proto__ === Person.prototype ) // true
// console.log( p1 )
console.log(p1.age) // 18
p1.say()

自定义 Person 构造函数

function Person(name) {
this.name = name;
}

// 实例化对象
let p1 = new Person(‘zf’);

// console.log( p1 )
/*
1. 对象都要一个__proto__属性,而且指向对应的原型
- 原型对象也是对象,那么也有__proto__,这个__proto__指向的也是一个原型对象
2. 所有对象通过__proto__查找原型,最终都会找到Obejct构造函数的原型
3. 顶级构造函数Object对应的原型 没有__proto__属性
- 如果非得访问则 返回值为null
/
// p1.proto 指向 Person对应的原型
// console.log( p1.proto === Person.prototype) // true
// p1.proto 原型对象 也有 proto 指向 Object构造函数对应的原型
// console.log( p1.proto.proto === Object.prototype) // true
// Object.prototype 原型 的__proto__ 是null
// console.log( Object.prototype.proto ) // null
/

1. 原型链的访问规则
对象访问属性的时候
会现在对象本身查找该属性,如果有则使用
如果在对象本身没有找到,则通过__proto__去对应的原型对象中查找,找到则使用
如果找到不,则继续通过__proto__往上去对应的对原型对象中查找,找到了则使用
以此类推,如果一直到找到Object.prototype这个原型对象中,没有这个属性,则返回undefined
2. 给对象属性赋值,都是给对象本身的属性赋值,如果原本没有该属性,就是添加(和原型没有任何关系)
*/
// 自定义 Person 构造函数
function Person(name) {
this.name = name;
}
// 给Person构造函数对应的原型添加 age属性name属性
Person.prototype.name = ‘zs’;
Person.prototype.age = 17;
// 给Object构造函数对应的原型添加 age属性name属性say方法
Object.prototype.name = ‘ls’;
Object.prototype.age = 18;
Object.prototype.say = function () {
console.log( ‘hi’ )
}

// 实例化对象
// let p1 = new Person(‘zf’);
// console.log( p1 )
// console.log( p1.name ) // ‘zf’
// console.log( p1.age ) // 17
// p1.say()
// console.log( p1.gender ) // undefined
// p1.eat() // 报错

// p1.age = 20;
// console.log( p1 )

继承

  • 继承是和构造函数相关的一个应用
  • 是指,让一个构造函数去继承另一个构造函数的属性和方法
  • 所以继承一定出现在 两个构造函数之间

一个小例子

  • 我们之前说,构造函数(类)是对一类行为的描述
  • 那么我们类这个概念其实也很抽象
  • 比如:
    • 我们说 国光 / 富士 都是 苹果的品种,那么我们就可以写一个 苹果类 来实例化很多品种出来
    • 苹果 / 这些东西都是水果的一种,那么我们就可以写一个 水果类
    • 说过的统一特点就是 / 水分大 ,而不同的水果有不同的特征
    • 那么我们就可以让 苹果类 来继承 水果类 的内容,然后再用 水果类 去实例化对象
    • 那么实例化出来的就不光有 苹果类 的属性和方法,还有 水果类 的属性和方法

继承的作用

  • 其实说到底,到底什么是继承

  • 我们之前说,在我们书写构造函数的时候,为了解决一个函数重复出现的问题

  • 我们把构造函数的 方法 写在了 prototype

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmqUHZmB-1666702196528)(./assets/构造函数.png)]

  • 这样,每一个实例使用的方法就都是来自构造函数的 prototype

  • 就避免了函数重复出现占用内存得到情况

  • 那么,如果两个构造函数的 prototype 中有一样的方法呢,是不是也是一种浪费

  • 所以我们把构造函数的prototype 中的公共的方法再次进行提取

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ngaDpFEY-1666702196530)(./assets/继承.png)]

  • 我们准备一个更公共的构造函数,让构造函数的 __proto__ 指向这个公共的构造函数的 prototype

常见的继承方式

  • 我们有一些常见的继承方式来实现和达到继承的效果

  • 我们先准备一个父类(也就是要让别的构造函数使用我这个构造函数的属性和方法)

    function Person() {
        this.name = 'Jack'
    }
    
    Person.prototype.sayHi = function () {
        cosnole.log('hello')
    }
    
  • 这个 Person 构造函数为父类

  • 让其他的构造函数来继承他

  • 当别的构造函数能够使用他的属性和方法的时候,就达到了继承的效果

原型继承
  • 原型继承,就是在本身的原型链上加一层结构

    function Student() {}
    Student.prototype = new Person()
    
借用构造函数继承
  • 把父类构造函数体借用过来使用一下而已

    function Student() {
      Person.call(this)
    }
    
组合继承
  • 就是把 原型继承借用构造函数继承 两个方式组合在一起

    function Student() {
      Person.call(this)
    }
    Student.prototype = new Person
    

ES6 的继承

  • es6 的继承很容易,而且是固定语法

    // 下面表示创造一个 Student 类,继承自 Person 类
    class Student extends Person {
        constructor () {
            // 必须在 constructor 里面执行一下 super() 完成继承 
            super()
        }
    }
    

    ES6的模块化

模块的思想,将对应的功能代码封装为一个模块(js代码 css代码 html代码)。

想要使用别人就导入,想要给别人用就导出。复用。

模块化的常用的模式

amd (在对应的加载之前导入)

cmd (在用的时候导入)

comment.js (基于amd和cmd之上)

es6的模块化的关键词(要想导入想要导出)

import 导入

export 导出

export的使用
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值