首页 前端知识 一文搞懂 js 原型和原型链

一文搞懂 js 原型和原型链

2024-09-04 23:09:47 前端知识 前端哥 406 790 我要收藏

文章目录

  • 一、前言
  • 二、原型
    • 2.1 概念
    • 2.2 获取原型的方法
      • 2.2.1 __proto__获取方式
      • 2.2.2 通过构造函数prototype 属性获取
      • 2.2.2 ES6 class 通过Object.getPrototypeOf()获取类原型
    • 2.3 通过原型实现继承
    • 2.4 原型的作用
  • 三、 原型链
  • 四、ES6实现继承
  • 五、综述


一、前言

原型和原型链是JavaScript中与对象有关的重要概念,但是部分前端开发者却不太理解,也不清楚原型链有什么用处。其实,学过其他面对对象语言的同学应该了解,对象是由类生成的实例,类与类之间有继承的关系。在ES6之前,JavaScript中并没有class,实现类和继承的方法就是使用原型。在我个人看来,JS中类和原型链的设计和语法由于一些历史或包袱问题而不易用,也不易于理解。因此在ES6中推出了class相关的语法,和其他语言更接近,也更易用。
ES6 class类
ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。(ECMAScript6入门教程 阮一峰)
虽然有了class,但是原型链相关的内容我们依然要掌握。不仅是因为作为前端开发者,我们要深入理解语法。而且在查看源码,以及实现一些复杂的面对对象写法时,依然是有用的。因此在这篇文章中,我们一起搞懂JavaScript中的原型和原型链。

二、原型

2.1 概念

JS的任何一个对象都拥有一个“原型对象”,他可以使用自己原型对象上的所有属性与方法。

2.2 获取原型的方法

2.2.1 __proto__获取方式

注意__是两个下划线。

// 1. 利用__proto__来调用原型
let cat = {
    name : '伽罗'
}
// 现在通过 cat.__proto__.eat 为cat的原型添加了一个方法 eat 这个方法来输出吃饭
cat.__proto__.eat=function() {
    console.log('吃饭')
}
cat.eat()

2.2.2 通过构造函数prototype 属性获取

function Cat(name,age){
    this.name=name
    this.age=age
}       
let cat = new Cat('伽罗',2)            
Cat.prototype.eat=function(){
    console.log('吃饭')
}
cat.eat()

2.2.2 ES6 class 通过Object.getPrototypeOf()获取类原型


class MyClass {
  constructor() {
    // 构造函数代码
  }
  classMethod() {
    // 类方法
  }
}
const prototype = Object.getPrototypeOf(MyClass);
console.log(prototype); // 输出 MyClass 的原型对象

2.3 通过原型实现继承

现在有一个管理系统。分为管理员和普通用户,普通用户只能登录,而管理员不光能登录还能删除用户。
Admin 可以使用自己的原型全部的方法。如果让自己的原型称为User的一个实例。即=new User()。那就相当于Admin 可以通过原型使用User的全部属性与方法。就实现了继承的思想。
在这里插入图片描述

function User(username,password){
    this.username=username
    this.password=password
 
    this.login=function(){
        console.log('登录');
    }
}
function Admin(){
    this.deletePerson=function(){
        console.log('删除用户');
    }
}
// 实现继承
Admin.prototype = new User()
let admin=new Admin()
admin.login()

2.4 原型的作用

1、模拟继承
2、规范日期:通过下述代码可以获取到当前日期,显示为 Wed Jul 06 2022 13:20:28 GMT+0800 (GMT+08:00)。但是 我不想要这种格式输出显示,我想显示成‘年/月/日’的格式,那么如何修改。

let date = new Date()
console.log(date);
let date = new Date()
Date.prototype.format = function() {
    let year = this.getFullYear()
    // 月份输出从0 开始 所以加一
    let month = this.getMonth()+1
    let date =  this.getDate()
    return `${year}${month}${date}`
}
console.log(date.format());
// 输出 2024年8月29日

三、 原型链

定义:JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
在这里插入图片描述
最后一个原型:原型链的尽头就是object。
在这里插入图片描述
还是管理员的例子,现在admin想调用login()。但是User() 里面没有login() 那么就会顺着原型链,继续向上寻找,直到找到objec,如果存在login()则输出,如果没有则报错。

function User(username,password){
   this.username = username
   this.password = password

 // this.login=function(){
 //     console.log('登录');
 // }
}
function Admin(){
   this.deletePerson=function(){
       console.log('删除用户');
   }
}
// 对objcet 上原型添加登录方法。
Object.prototype.login = function(){
    console.log('Object上的登录');
}
User.prototype = new Object()
Admin.prototype = new User()
let admin=new Admin()
admin.login()

四、ES6实现继承

那么在ES6之前不可以使用类,而JS在ES6之后引入了类的概念,那么就可以直接使用继承的思维了。
上述关于管理与普通用户的例子就可以修改ES6之后的写法。

class User{
  constructor(username,password){
      this.username=username
      this.password=password
  }
  login(){
      console.log('登录');
  }
}
 
class Admin extends User{
  deletePerson(){
      console.log('删除用户');
  }
}
 
let admin = new Admin()
admin.login()

五、综述

总体看来,虽然使用原型链确实可以实现类和继承的等面对对象特性,但是相比于其他语言更晦涩且不容易理解。更推荐ES6 使用class类来实现继承。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17655.html
标签
评论
发布的文章

javascript jQuery

2024-09-21 22:09:33

【若依】表格固定列宽

2024-09-21 22:09:30

Knockout-jQueryUI 使用指南

2024-09-21 22:09:29

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!