从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
```

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

相关推荐
漫路在线3 小时前
JS逆向-某易云音乐下载器
开发语言·javascript·爬虫·python
不爱吃糖的程序媛3 小时前
浅谈前端架构设计与工程化
前端·前端架构设计
BillKu4 小时前
Vue3 Element Plus 对话框加载实现
javascript·vue.js·elementui
郝YH是人间理想5 小时前
系统架构设计师案例分析题——web篇
前端·软件工程
Evaporator Core5 小时前
深入探索:Core Web Vitals 进阶优化与新兴指标
前端·windows
初遇你时动了情5 小时前
html js 原生实现web组件、web公共组件、template模版插槽
前端·javascript·html
QQ2740287565 小时前
Soundness Gitpod 部署教程
linux·运维·服务器·前端·chrome·web3
前端小崔5 小时前
从零开始学习three.js(18):一文详解three.js中的着色器Shader
前端·javascript·学习·3d·webgl·数据可视化·着色器
哎呦你好6 小时前
HTML 表格与div深度解析区别及常见误区
前端·html
运维@小兵6 小时前
vue配置子路由,实现点击左侧菜单,内容区域显示不同的内容
前端·javascript·vue.js