• JavaScript 进阶03


    编程思想

    面向过程

    面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用

    面向对象

    面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。

    在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工。

    面向对象编程具有灵活、代码可复用、容易维护和开发的优点,更适合多人合作的大型软件项目。

    面向对象的特性:

    构造函数

    通过面向对象的构造函数实现的封装:

    <script>
      function Person() {
        this.name = '佚名'
        // 设置名字
        this.setName = function (name) {
          this.name = name
        }
        // 读取名字
        this.getName = () => {
          console.log(this.name)
        }
      }
      // 实例对像,获得了构造函数中封装的所有逻辑
      let p1 = new Person()
      p1.setName('小明')
      console.log(p1.name)
    
      // 实例对象
      let p2 = new Person()
      console.log(p2.name)
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    构造函数存在浪费内存的问题

    原型对象

    构造函数通过原型分配的函数是所有对象所共享的

    • 构造函数的 prototype 属性为原型(对象)
    • 原型对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存
    • 公共的方法放在 prototype 对象上
    • 构造函数和原型对象中的this 都指向实例对象
    <script>
      function Person() {
      }
      // 每个函数都有 prototype 属性
      console.log(Person.prototype)
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <script>
      function Person() {
        // 此处未定义任何方法
      }
      // 为构造函数的原型对象添加方法
      Person.prototype.sayHi = function () {
        console.log('Hi~');
      }
    	
      // 实例化
      let p1 = new Person();
      p1.sayHi(); // 输出结果为 Hi~
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    构造函数 Person 中未定义任何方法,这时实例对象调用了原型对象中的方法 sayHi,接下来改动一下代码:

    <script>
      function Person() {
        // 此处定义同名方法 sayHi
        this.sayHi = function () {
          console.log('嗨!');
        }
      }
    
      // 为构造函数的原型对象添加方法
      Person.prototype.sayHi = function () {
        console.log('Hi~');
      }
    
      let p1 = new Person();
      p1.sayHi(); // 输出结果为 嗨!
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    构造函数 Person 中定义与原型对象中相同名称的方法,这时实例对象调用则是构造函中的方法 sayHi

    当访问对象的属性或方法时,先在当前实例对象是查找,然后再去原型对象查找,并且原型对象被所有实例共享。

    constructor 属性

    每个原型对象里面都有个constructor 属性

    作用:该属性指该回原型对象的构造函数

    使用场景:

    如果有多个对象的方法,我们可以给原型对象采取对象形式赋值.

    但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了

    此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

    function Fu(){ 
    }
    Fu.prototype={
        constructor:Fu,
        sing:function (){
            console.log('我爱唱歌')
        },
        dance:function (){
            console.log('跳舞')
        }}
    console.log(Fu.prototype.constructor) //如果不在原型函数中添加constructor会输出object
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对象原型

    每个对象都有 __proto__指向构造函数的 prototype 原型对象

    function Fu(){}
    const fu=new Fu()
    console.log(fu.__proto__===Fu.prototype)//Ture
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    原型继承

    JavaScript 中大多是借助原型对象实现继承的特性。

    <body>
      <script>
          //公共的部分放到原型上
        function Person() {
          this.eyes = 2
          this.head = 1
        }
        function Woman() {
        } 
        //Woman 通过原型来继承 Person
        Woman.prototype = new Person()
        // 指回原来的构造函数
        Woman.prototype.constructor = Woman
    
        // 给女人添加一个方法
        Woman.prototype.baby = function () {
          console.log('宝贝')
        }
        const red = new Woman()
        console.log(red)
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    原型链

    基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

    <body>
      <script>
        // function Objetc() {}
        console.log(Object.prototype)
        console.log(Object.prototype.__proto__)
    
        function Person() {
    
        }
        const ldh = new Person()
        // console.log(ldh.__proto__ === Person.prototype)
        // console.log(Person.prototype.__proto__ === Object.prototype)
        console.log(ldh instanceof Person)
        console.log(ldh instanceof Object)
        console.log(ldh instanceof Array)
        console.log([1, 2, 3] instanceof Array)
        console.log(Array instanceof Object)
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。

    ② 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)

    ③ 如果还没有就查找原型对象的原型(Object的原型对象)

    ④ 依此类推一直找到 Object 为止(null)

    ⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

    ⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

  • 相关阅读:
    SpringMVC之框架搭建&开发实例&请求的处理流程
    238-h148 排序链表
    .Net6与Framework不同方式获取文件哈希值的性能对比
    《HelloGitHub》第 95 期
    【kali-信息收集】(1.3)探测网络范围:DMitry(域名查询工具)、Scapy(跟踪路由工具)
    信息学奥赛一本通:1104:计算书费
    前端与后端如何开发不阻塞?
    C++提高编程:02 STL入门
    嵌入式Linux驱动开发 02:将驱动程序添加到内核中
    这些论文的作者居然是猫、狗、仓鼠……
  • 原文地址:https://blog.csdn.net/tuoluoo/article/details/136354150