JS进阶-原型

avatar
作者
筋斗云
阅读量:2

学习目标:

  • 掌握原型

学习内容:

  1. 原型
  2. constructor属性
  3. 对象原型
  4. 原型继承
  5. 原型链
  6. 综合案例

原型:

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

JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象,所以我们也称为原型对象。

这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存。

我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。

构造函数和原型对象中的this都指向 实例化的对象。

在这里插入图片描述

<title>原型</title> </head>  <body>   <script>     // 构造函数  公共的属性和方法 封装到 Star 构造函数里面了     // 1.公共的属性写到 构造函数里面     function Star(uname, age) {       this.uname = uname       this.age = age       // this.sing = function () {       //   console.log('唱歌')       // }     }     // 2. 公共的方法写到原型对象身上   节约了内存     Star.prototype.sing = function () {       console.log('唱歌')     }     const ldh = new Star('刘德华', 55)     const zxy = new Star('张学友', 58)     ldh.sing() //调用     zxy.sing() //调用     // console.log(ldh === zxy)  // false     console.log(ldh.sing === zxy.sing)      // console.dir(Star.prototype)   </script>  </body> 

在这里插入图片描述

  • 小结
  1. 原型是什么?

一个对象,我们也称为prototype为原型对象

  1. 原型的作用是什么?

共享方法。
可以把那些不变的方法,直接定义在prototype对象上。

  1. 构造函数和原型里面的this指向谁?

实例化的对象。

  • 原型-this指向

构造函数和原型对象中的this指向 实例化的对象。

<title>构造函数和原型的this指向</title> </head>  <body>   <script>     let that     function Star(uname) {       // that = this       // console.log(this)       this.uname = uname     }     // 原型对象里面的函数this指向的还是 实例对象 ldh     Star.prototype.sing = function () {       that = this       console.log('唱歌')     }     // 实例对象 ldh        // 构造函数里面的 this 就是  实例对象  ldh     const ldh = new Star('刘德华')     ldh.sing()     console.log(that === ldh)  //true   </script>  </body> 
  • 练习
 <title>练习-给数组扩展方法</title> </head>  <body>   <script>     //自己定义 数组扩展方法 求和  和  最大值     //1.我们定义的这个方法,任何一个数组实例对象都可以使用     //2.自定义的方法写到 数组.prototype 身上     //1.最大值     const arr = [1, 2, 3]     Array.prototype.max = function () {       //展开运算符       return Math.max(...this)       //原型函数里面的this指向谁?  实例对象  arr     }      //2.最小值     Array.prototype.min = function () {       //展开运算符       return Math.min(...this)       //原型函数里面的this指向谁?  实例对象  arr     }     console.log(arr.max())     console.log([2, 5, 9].max())     console.log(arr.min())      // const arr = new Array(1,2)     // console.log(arr)      //3.求和方法     Array.prototype.sum = function () {       return this.reduce((prev, item) => prev + item, 0)     }     console.log([1, 2, 3].sum())     console.log([11, 21, 31].sum())    </script>  </body> 

constructor属性:

每个原型对象里面都有个constructor属性(constructor 构造函数)。

作用:该属性指向该原型对象的构造函数简单理解,就是指向我的爸爸,我是有爸爸的孩子。
在这里插入图片描述

  • 使用场景

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

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

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

 <title>constructor属性</title> </head> <body>   <script>       // constructor  单词 构造函数       // Star.prototype.sing = function () {     //   console.log('唱歌')     // }     // Star.prototype.dance = function () {     //   console.log('跳舞')     // }     function Star() {     }     // console.log(Star.prototype)     Star.prototype = {       // 从新指回创造这个原型对象的 构造函数       constructor: Star,       sing: function () {         console.log('唱歌')       },       dance: function () {         console.log('跳舞')       },     }     console.log(Star.prototype)     // console.log(Star.prototype.constructor)       // const ldh = new Star()     // console.log(Star.prototype.constructor === Star) //true   </script>    </body> 
  • 小结
  1. constructor 属性的作用是什么?

指向该原型对象的构造函数。


对象原型:

对象都会有一个属性_proto_指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype 。

原型对象的属性和方法,就是因为对象有_proto_原型的存在。
在这里插入图片描述

  • 注意
  1. _proto_是JS非标准属性。
  2. [[_proto_]]_proto_意义相同。
  3. 用来表明当前实例对象指向哪个原型对象prototype。
  4. _proto_对象原型里面也有一个constructor属性,指向创建该实例对象的构造函数。
 <title>对象原型</title> </head>  <body>   <script>     function Star() {      }     const ldh = new Star()     // 对象原型__proto__ 指向 改构造函数的原型对象     console.log(ldh.__proto__)     // console.log(ldh.__proto__ === Star.prototype)  //true     // 对象原型里面有constructor 指向 构造函数 Star     console.log(ldh.__proto__.constructor === Star)  //true   </script>  </body> 
  • 小结
  1. prototype是什么?哪里来的?

原型(原型对象)。
构造函数都自动有原型。

  1. constructor属性在哪里?作用干啥的?

prototype原型和对象原型_proto_里面都有。
指向创建实例对象/原型的构造函数

  1. _proto_属性在哪里?指向谁?

在实例对象里面。
指向原型prototype

  • 练习
function Star() {      }     const ldh = new Star()     // 对象原型__proto__ 指向 改构造函数的原型对象     console.log(ldh.__proto__)     // console.log(ldh.__proto__ === Star.prototype)  //true     // 对象原型里面有constructor 指向 构造函数 Star     console.log(ldh.__proto__.constructor === Star)  //true 

在这里插入图片描述


原型继承:

继续是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript中大多是借助原型对象实现继承的特性。

<title>原型继承</title> </head>  <body>   <script>     //继续抽取  公共的部分放到原型上     // const Person = {     //   eyes: 2,     //   head: 1     // }     //构造函数 new出来的对象  结构一样,但是对象不一样     function Person() {       this.eyes = 2       this.head = 1     }       //女人  构造函数  继承  想要继承Person     function Woman() {       this.eyes = 2       this.head = 1     }     //Woman 通过原型来继承 Person     // 父构造函数(父类)   子构造函数(子类)     // 子类的原型 =  new 父类       Woman.prototype = new Person()  // {eyes: 2, head: 1}      //指回原来的构造函数     Woman.prototype.constructor = Woman      //给女人添加一个方法  来姨妈     Woman.prototype.yuejing = function () {       console.log('来姨妈')     }     const red = new Woman()     console.log(red)     // console.log(Woman.prototype)        //男人 构造函数  继承  想要继承Person     function Man() {       this.eyes = 2       this.head = 1     }     //Man 通过原型来继承 Person     Man.prototype = new Person()     //指回原来的构造函数     Man.prototype.constructor = Man     const blue = new Man()     console.log(blue)     // console.log(Man.prototype)   </script>  </body> 

原型链:

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

<title>原型链</title> </head>  <body>   <script>     // function Objetc() {}     console.log(Object.prototype)     console.log(Object.prototype.__proto__) //null      function Person() {      }     const ldh = new Person()     // console.log(ldh.__proto__ === Person.prototype) //true     // console.log(Person.prototype.__proto__ === Object.prototype)  //true     console.log(ldh instanceof Person) //true     console.log(ldh instanceof Object) //true     console.log(ldh instanceof Array)  //false     console.log([1, 2, 3] instanceof Array) //true     console.log(Array instanceof Object) //true   </script>  </body> 

在这里插入图片描述

  • 原型链-查找规则
  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
  2. 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)。
  3. 如果还没有就查找原型对象的原型(Object的原型对象)。
  4. 依次类推一直找到Object为止(null)。
  5. __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
  6. 可以使用instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

综合案例:

<!DOCTYPE html> <html lang="en">  <head>   <meta charset="UTF-8">   <meta name="viewport" content="width=device-width, initial-scale=1.0">   <title>综合案例-消息提示对象封装</title>   <style>     .modal {       width: 300px;       min-height: 100px;       box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);       border-radius: 4px;       position: fixed;       z-index: 999;       left: 50%;       top: 50%;       transform: translate3d(-50%, -50%, 0);       background-color: #fff;     }      .modal .header {       line-height: 40px;       padding: 0 10px;       position: relative;       font-size: 20px;     }      .modal .header i {       font-style: normal;       color: #999;       position: absolute;       right: 15px;       top: -2px;       cursor: pointer;     }      .modal .body {       text-align: center;       padding: 10px;     }      .modal .footer {       display: flex;       justify-content: flex-end;       padding: 10px;     }      .modal .footer a {       padding: 3px 8px;       background: #ccc;       text-decoration: none;       color: #fff;       border-radius: 2px;       margin-right: 10px;       font-size: 14px;     }      .modal .footer a.submit {       background-color: #369;     }   </style> </head>  <body>   <button id="delete">删除</button>   <button id="login">登录</button>    <!-- <div class="modal">       <div class="header">温馨提示 <i>x</i></div>       <div class="body">您没有删除权限操作</div>     </div> -->   <script>     //1.Modal 构造函数封装 - 模态框     function Modal(title = '', message = '') {       // console.log(title, message)       //创建 modal模态框盒子       //1.1创建div标签       this.modalBox = document.createElement('div')       //1.2给div标签添加类名为modal       this.modalBox.className = 'modal'       //1.3 modal 盒子内部填充2个div标签并且修改文字内容       this.modalBox.innerHTML = `       <div class="modal">       <div class="header">${title} <i>x</i></div>       <div class="body">${message}</div>     </div>              `       console.log(this.modalBox)       }      // new Modal('温馨提示', '您没有删除权限操作')     // new Modal('友情提示', '您还没有登录呢')      //2.给构造函数原型对象挂载 open 方法     Modal.prototype.open = function () {       //先来判断页面中是否有modal盒子,如果有先删除,否则继续添加       const box = document.querySelector('.modal')       box && box.remove()       //注意这个方法不要用箭头函数       //把刚才创建的modalBox 显示到页面body中       document.body.append(this.modalBox)        //要等着盒子显示出来,就可以绑定点击事件了       this.modalBox.querySelector('i').addEventListener('click', () => {         //这个地方需要用到箭头函数         //这个this指向  实例对象         this.close()       })     }      //3.给构造函数原型对象挂载 close方法     Modal.prototype.close = function () {       this.modalBox.remove()     }         //测试一下 点击 删除按钮     document.querySelector('#delete').addEventListener('click', () => {       //先调用 Modal 构造函数       const del = new Modal('温馨的提示', '您没有删除权限操作')       //实例对象调用open方法       del.open()     })      //测试一下 点击 删除按钮     document.querySelector('#login').addEventListener('click', () => {       //先调用 Modal 构造函数       const login = new Modal('友情的提示', '您还没有登录呢')       //实例对象调用open方法       login.open()     })   </script>  </body>  </html> 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!