3.JS学习篇:面向对象编程->构造函数->原型和原型链

1.面向对象编程

1. 基本概念

在前端开发中,面向对象的编程(OOP)的基本概念如下:

对象(Object)

        1. 在前端中,对象可以表示页面元素、用户信息、数据模型等。

例如,一个表示用户的对象可能具有用户名、密码、电子邮件等属性,以及登录、注册等方法。

类(Class)

        1. 用于定义对象的模板。比如创建一个 Button 类来表示页面上的按钮,规定其样式、行为等特征。

属性(Attribute)

        1. 存储对象的数据。对于一个前端组件类,属性可能包括颜色、大小、是否可见等。

方法(Method)

        1. 定义对象的行为或操作。如在 Form 类中,可能有提交表单、验证表单等方法。

封装(Encapsulation)

        1. 将相关的属性和方法组合在一起,并隐藏内部实现细节。在前端,可能将一个组件的内部逻辑封装起来,只暴露必要的接口供外部使用。

继承(Inheritance)

        1. 前端中,组件之间可以通过继承来共享和扩展功能。例如,一个特定类型的输入框组件可以继承自通用的输入框组件。

多态(Polymorphism)

        1. 同一方法在不同的对象或组件中可以有不同的实现。比如,不同类型的按钮点击时可能执行不同的具体操作。

Class Product {
    constructor (name, price, description) {
        this.name = name
        this.price = price
        this.description = description
    }

    displayDetails () {
        return `产品名:${this.name},价格:${this.price},描述:${this.description}`
    }
}
2. 使用场景

在前端开发过程中,面向对象编程有很多的使用场景:

1.组件开发

        1. 构建可复用的UI组件,如按钮,输入框,模态框等。每个组件可以定义为一个类,具有自己的属性,方法,事件处理逻辑等。

        2. 例如创建一个Modal类来管理模态框的显示,隐藏,内容设置。

2.页面模块管理

        1. 将页面的不同功能封装为类,便于组织和维护代码。

        2. 比如:对一个购物页面,可以有Cart类管理购物车,ProductList类管理商品列表。

3.数据模型

        1. 定义与后端数据交互的模型类,处理数据的获取,更新和验证

        2. 如User类来表示用户信息,Order类表示订单信息。

4.动画效果

        1. 创建动画类来控制元素的动画效果,如淡入淡出、滑动等。

        2. 例如 FadeAnimation 类和 SlideAnimation 类。

5.表单处理

        1. 构建表单类来处理表单元素的验证、提交和数据处理。

        2. 像 Form 类可以包含验证规则和提交方法。

6.状态管理

        1. 结合状态管理库(如 Redux),使用类来组织和操作状态相关的逻辑。

7.插件开发

         1. 开发可插拔的前端插件,如图表插件、地图插件等。

8.游戏开发

        1. 在前端游戏中,创建角色、道具、场景等类来管理游戏元素的行为和状态。

class Counter {
    constructor () {
        this.count = 0
    }

    increment () {
        this.count++
    }

    decrement () {
        if (this.count > 0) {
            this.count--
        }
    }

    getCount () {
        return this.count
    }
}

let counter = new Counter()
counter.increment()
console.log(counter.getCount())
3. 底层原理

在前端开发中,面向对象编程的底层原理主要基于 JavaScript 的对象和原型机制。当创建一个类时,实际上 JavaScript 是通过以下方式来实现类似面向对象的特性:

1. 构造函数

        1. 类中的构造函数在创建对象实例时被调用。它负责初始化对象的属性。

        2. 底层上,它就是一个普通的函数,但通过 new 关键字调用时,会执行一系列特殊的操作,创建一个新的对象,并将这个新对象的 __proto__ 指向构造函数的 prototype 属性。

2. 原型对象(Prototype)

        1. 每个函数都有一个 prototype 属性,当通过构造函数创建对象实例时,实例的 __proto__ 会指向这个原型对象。

        2. 原型对象上定义的方法和属性可以被实例共享和访问。

3. 原型链

        当访问对象的属性或方法时,如果对象本身没有,JavaScript 会沿着对象的 __proto__ 链向上查找,直到找到或者到达 Object.prototype(原型链的顶端)。

function Person (name, age) {
    this.name = name
    this.age =age
}

Person.prototype.sayHello = function () {
    console.log(`Hello, I am ${this.name}, ${this.age} years old`)
}

let person1 = new Person('wikiHong', 18)

当创建 person1 实例时,person1 具有自己的 name 和 age 属性,而 sayHello 方法是通过原型链从 Person.prototype 上获取的。

这种基于原型的机制使得 JavaScript 能够在一定程度上实现面向对象编程的特性,同时保持其灵活性和动态性。

2.构造函数

1. 基本概念

在前端开发中,构造函数(Constructor Function)是用于创建和初始化对象的特殊函数。

构造函数具有以下基本概念和特点:

        1. 命名约定,通常使用首字母大写的方式来命名构造函数,以便与普通函数区分。

        2. 作用:主要用于创建对象实例,并为实例设置初始的属性和状态。

        3. this 关键字:在构造函数内部,this 指向正在创建的新对象。通过给 this 赋值来设置对象的属性。

        4. 实例创建:使用 new 关键字来调用构造函数,从而创建新的对象实例。

function Person (name, age) {
    this.name = name
    this.age = age
    this.sayHello = function () {
        console.log(`Hello, I am ${this.name}, ${this.age} years old`)
    }
}

let person1 = new Person('wikihong', 18)
let person2 = new Person('tuantuan', 8)

在上述示例中,Person 是构造函数,通过 new Person(...) 创建了 person1 和 person2 两个不同的对象实例,它们各自具有独立的 name 和 age 属性,以及共享的 sayHello 方法。

2. 使用场景

在前端开发中,构造函数有以下一些常见的使用场景:

1. 创建具有相同结构和初始属性的对象集合:比如创建一组用户对象,每个用户都有用户名、密码、邮箱等属性。

2. 模拟类的行为:在 JavaScript 中,虽然没有像传统面向对象语言那样严格的类,但构造函数结合原型可以实现类似类的功能。

3. 初始化复杂的对象状态:当对象的初始状态需要进行一系列计算或配置时,构造函数可以集中处理这些逻辑。

4. 与特定库或框架的集成:某些前端框架或库可能要求或推荐使用构造函数来创建特定类型的组件或对象。

5. 数据封装和组织将相关的数据和操作封装在一个对象中,通过构造函数进行初始化和设置。

例如,如果要创建一个表示汽车的对象:

function Car (make, model, year) {
    this.make = make
    this.model = model
    this.year = year
    this.startEngine = function () {
        console.log(`the ${this.make} ${this.model} engine is starting`)
    }
}

let myCar = new Car('Toyota', 'Camry', 2024)
myCar.startEngine()
3. 底层原理

在前端 JavaScript 中,构造函数的底层原理主要涉及以下几个方面:

1. new 操作符的作用

        1. 当使用 new 操作符调用构造函数时,会执行以下步骤:

                1. 创建一个新的空对象。

                2. 将这个新对象的 __proto__ 指向构造函数的 prototype 属性,从而建立原型链。

                3. 把构造函数中的 this 绑定到这个新创建的对象上。

                4. 执行构造函数中的代码,为新对象设置属性。

                5. 如果构造函数没有显式返回一个对象,那么 new 操作就会返回这个新创建并初始化的对象。

2. 原型(Prototype)

        1. 每个构造函数都有一个 prototype 属性,它是一个对象。通过构造函数创建的对象实例,可以通过 __proto__ 访问到这个原型对象。

        2. 原型对象上的属性和方法可以被实例共享,从而节省内存。

3. 继承机制

        1. 基于原型链实现继承。子类的构造函数的 prototype 对象指向父类的实例,从而实现属性和方法的继承。

function Person (name, age) {
    this.name = name
    this.age = age
}

person.prototype.sayHello = function () {
    console.log(`Hello, I am ${this.name}, ${this.age} years old.`)
}

当创建实例 let person = new Person('wikiHong', 18) 时,底层发生的步骤包括创建新对象、设置原型链、绑定 this 并执行构造函数中的代码,使得 person 对象具有 name 和 age 属性,并且能够访问 sayHello 方法。

3.原型和原型链

1. 基本概念

在前端开发中,原型(Prototype)和原型链(Prototype Chain)是 JavaScript 中实现面向对象特性和对象属性查找的重要概念。

原型(Prototype)

每个函数都有一个 prototype 属性,这个属性指向一个对象,称为该函数的原型对象。当通过这个函数创建对象实例时,实例可以通过 __proto__ 访问到函数的原型对象。

原型对象的主要作用是共享方法和属性。如果实例自身没有某个属性或方法,JavaScript 引擎会沿着原型链在原型对象上查找。

原型链(Prototype Chain)

对象通过 __proto__ 链接到其构造函数的原型对象,而原型对象本身也有 __proto__ ,它指向其构造函数的原型对象,这样就形成了一个链条,称为原型链。

当查找一个对象的属性或方法时,如果对象本身没有,就会沿着原型链向上查找,直到找到或者到达原型链的顶端(即 Object.prototype )。

function Parent() {}
Parent.prototype.someMethod = function() {
  console.log('Parent method');
};

function Child() {}
Child.prototype = new Parent();

let childInstance = new Child();
childInstance.someMethod(); 
在这个例子中,创建了 Parent 和 Child 两个构造函数。Child 的原型对象被设置为 Parent 的一个实例,从而建立了继承关系。当 childInstance 调用 someMethod 方法时,如果自身没有,就会沿着原型链在 Child 的原型对象(即 Parent 的实例)上找到并执行。
2. 使用场景

在前端开发中,原型和原型链有以下一些常见的应用场景:

1.实现继承

        1.可以通过将子类的原型对象设置为父类的实例,从而实现属性和方法的继承,减少代码重复。

        2.例如,创建一个通用的组件类,然后基于它派生出具有特定功能的子类组件。

2.共享方法和属性

        1. 把常用的方法定义在原型上,多个实例可以共享这些方法,节省内存。

        2. 比如,为一个自定义的对象类型定义一些通用的操作方法。

3.模拟类的行为

        1. 虽然 JavaScript 不是传统的基于类的语言,但原型和原型链可以帮助模拟类的特性。

4.扩展内置对象

        1.可以为 JavaScript 的内置对象(如 Array 、 Object 等)的原型添加自定义方法,以扩展其功能。

        2.例如,为 Array 添加一个自定义的排序方法。

5.库和框架的实现

        1.许多前端库和框架内部使用原型和原型链来构建其对象系统和组件架构。

6.插件开发

        1.在开发插件时,利用原型和原型链来扩展现有对象的功能。

function Animal(name) {
  this.name = name;
}

Animal.prototype.sayName = function() {
  console.log(`My name is ${this.name}`);
};

let dog = new Animal('Dog');
let cat = new Animal('Cat');

dog.sayName(); 
cat.sayName(); 
在这个例子中,sayName 方法通过原型共享,减少了内存占用。
3. 底层原理

在前端的 JavaScript 中,原型和原型链的底层原理主要基于以下几个方面:

1. 对象的创建

        1.当使用 new 操作符调用一个构造函数来创建对象时,会发生以下步骤:

        2.将这个新对象的内部 [[Prototype]](在 JavaScript 中通过 __proto__ 访问)属性设置为构造函数的 prototype 属性所指向的对象。

        3.执行构造函数内部的代码,将属性和方法添加到这个新对象上。

        4.返回这个新创建的对象。

2. 原型对象

        每个函数在创建时,都会自动获得一个 prototype 属性,这个属性指向一个原型对象。这个原型对象默认包含一个 constructor 属性,它指向该函数本身。

3.原型链:    

        由于对象的 __proto__ 指向其构造函数的原型对象,而原型对象本身也是一个对象,也有自己的 __proto__ ,如果这个 __proto__ 不为 null ,就形成了一条链,称为原型链。

        当访问一个对象的属性或方法时,JavaScript 引擎首先在对象本身查找,如果没有找到,就会沿着原型链向上查找,直到找到或者到达原型链的顶端(即 Object.prototype ,其 __proto__ 为 null )。

function Parent() {}
Parent.prototype.parentMethod = function() {
  console.log('Parent Method');
};

function Child() {}
Child.prototype = new Parent();

let childObj = new Child();
childObj.parentMethod(); 

当执行 childObj.parentMethod() 时,如果 childObj 自身没有 parentMethod 方法,JavaScript 引擎会沿着 childObj 的 __proto__ 找到 Child 的原型对象,由于 Child 的原型对象是 Parent 的实例,其中也没有 parentMethod 方法,就会继续沿着其 __proto__ 找到 Parent 的原型对象,从而找到并执行 parentMethod 方法。

  • 31
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值