从0开始完全掌握JS中的原型

前言

许多刚入门前端的朋友可能会难以理解js中的原型和原型链,对这个概念非常模糊,然而,理解原型链是成为JavaScript高手的必备技能之一 。下面,我将详细讲解这些概念,希望能帮助你更好地掌握它们。

在讲原型之前,我们先了解下js的对象

对象

对象是数据结构的一种基本形式,用于存储各种类型的数据。对象可以被视为一组无序的键值对(key-value pairs),其中键(key)通常是字符串或符号(Symbol),值(value)可以是任何数据类型,包括数字、字符串、布尔值、数组、函数或其他对象。

  • 创建对象的方式

    • 对象字面量

      这是最简单且常见的创建对象的方式,只需要用一个{}来包含键值对就行,它可以在创建对象后随时添加、修改或删除属性和方法。但只适合创建单个对象,不适合批量创建多个具有相同属性和方法的对象。

    js 复制代码
    let mei = {
      name:'小美',
      age:18,
      hometown:'北京',
      sayHi(){
        console.log(`我叫${this.name},来自${this.hometown}`)
      }
    }
    mei.sayHi() // 我叫小美,来自北京
    • class类

      ES6 引入了class关键字,使得面向对象编程更加简洁直观,比较类似于传统面向对象语言(如Java或C#)中的类。

    js 复制代码
    class Person {
    constructor(name, age) {
      this.name = name;
      this.age = age;
      console.log(this.name + this.age);
      
    }
    
    greet() {
      console.log('你好,我是' + this.name);
    }
    }
    
    let person1 = new Person('张三', 28); //张三28
    let person2 = new Person('李四', 30); //李四30
    person1.greet(); // 你好,我是张三
    • 构造函数
    1. 构造函数通常用于实现面向对象编程中的类(尽管js并没有真正的类,直到ES6才引入了class关键字)。构造函数通过new运算符调用,通常是首字母大写用以区分普通函数,但这并不是强制性的,只是大家约定俗成的一种规矩
    js 复制代码
    function Person(name,age){
      console.log(this); // 会打印global
      this.name = name
      this.age = age
    }
    Person('小明',18) // 普通函数调用
    let xiaoming = new Person('小明',18) // 构造函数调用
    1. 构造函数,可以创建多个具有相同属性和方法的对象实例,由this指针指向实例对象。
    js 复制代码
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    let person1 = new Person('张三', 28);
    let person2 = new Person('李四', 30);
    // 检查 this 指向
    console.log(person1.name); // 输出: 张三
    console.log(person2.name); // 输出: 李四

原型和原型链

原型

JavaScript对象都有一个内部属性 [[Prototype]],它指向该对象的原型对象。 __proto__ 是一个访问器属性,允许你在对象上读取或设置 [[Prototype]]属性,通过构造函数创建的对象拥有构造函数内部定义的属性和方法

scss 复制代码
```js
function Person(name, age) {
    this.name = name;
    this.age = age;
}

// 为原型对象添加一个方法
Person.prototype.greet = function() {
    console.log('你好,我是' + this.name);
};

let person1 = new Person('张三', 28);

// 访问 person1 的原型对象
console.log(person1.__proto__); // 输出: Person { greet: [Function: greet] }

// 检查 person1 的原型对象是否等于 Person.prototype
console.log(person1.__proto__ === Person.prototype); // 输出: true

// 调用实例上的方法
person1.greet(); // 输出: 你好,我是张三

// 动态添加一个新方法到原型对象
Person.prototype.sayHello = function() {
    console.log('你好,世界!');
};

// 调用新添加的方法
person1.sayHello(); // 输出: 你好,世界!

// 创建另一个 Person 实例
let person2 = new Person('李四', 30);

// 调用新添加的方法
person2.sayHello(); // 输出: 你好,世界!

// 修改 person1 的原型对象
person1.__proto__ = {
    greet: function() {
        console.log('你好,我是新的' + this.name);
    },
    sayBye: function() {
        console.log('再见!');
    }
};

// 再次调用 person1 上的方法
person1.greet(); // 输出: 你好,我是新的张三
person1.sayBye(); // 输出: 再见!
```

原型链

试访问一个对象的某个属性或方法时,如果该对象自身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到该属性或方法为止,或者到达原型链的末端(即 null)。

ini 复制代码
```js
let baseObject = {
    baseMethod: function() {
        console.log('这是基础方法');
    }
};

// 定义一个中间对象,继承自 baseObject
let middleObject = Object.create(baseObject);
middleObject.middleMethod = function() {
    console.log('这是中间方法');
};

// 定义一个最终对象,继承自 middleObject
let finalObject = Object.create(middleObject);
finalObject.finalMethod = function() {
    console.log('这是最终方法');
};

// 尝试访问 finalObject 的属性和方法
finalObject.finalMethod(); // 输出: 这是最终方法
finalObject.middleMethod(); // 输出: 这是中间方法
finalObject.baseMethod(); // 输出: 这是基础方法

// 尝试访问一个不存在的属性
console.log(finalObject.someProperty); // 输出: undefined

// 检查原型链
console.log(finalObject.__proto__ === middleObject); // 输出: true
console.log(middleObject.__proto__ === baseObject); // 输出: true
console.log(baseObject.__proto__ === Object.prototype); // 输出: true
console.log(Object.prototype.__proto__ === null); // 输出: true
```

通过原型对象,可以实现方法的共享,提高性能,增强了代码的灵活性和可维护性,希望本文能帮助你更好地理解原型。

相关推荐
用户38022585982413 分钟前
vue3源码解析:响应式机制
前端·vue.js
bo5210015 分钟前
浏览器渲染机制详解(包含渲染流程、树结构、异步js)
前端·面试·浏览器
普通程序员21 分钟前
Gemini CLI 新手安装与使用指南
前端·人工智能·后端
Web小助手21 分钟前
js高级程序设计(日期)
javascript
Web小助手22 分钟前
js高级程序设计(4/5章节)
javascript
山有木兮木有枝_23 分钟前
react受控模式和非受控模式(日历的实现)
前端·javascript·react.js
十盒半价24 分钟前
从递归到动态规划:手把手教你玩转算法三剑客
javascript·算法·trae
流口水的兔子24 分钟前
作为一个新手,如果让你去用【微信小程序通过BLE实现与设备通讯】,你会怎么做,
前端·物联网·微信小程序
多啦C梦a28 分钟前
🪄 用 React 玩转「图片识词 + 语音 TTS」:月影大佬的 AI 英语私教是怎么炼成的?
前端·react.js
呆呆的心28 分钟前
大厂面试官都在问的 WEUI Uploader,源码里藏了多少干货?🤔
前端·微信·面试