JS宏进阶: 工厂函数与构造函数

一、构造函数

在JavaScript中,构造函数是一种用于创建和初始化对象的特殊函数。构造函数的名字通常以大写字母开头,以区分于普通函数。通过new关键字调用构造函数,可以创建一个新的实例对象,并自动执行构造函数内部的代码来初始化这个对象。

1、构造函数的定义

javascript 复制代码
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayHello = function() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    };
}

上述示例,是一个似曾相识的示例。因为在"函数、对象和类(一)"这一章节中简单讲解this关键字时的一个示例。在这个例子中,Person是一个构造函数,它接受两个参数name和age,并将它们赋值给新对象的属性。同时,它还定义了一个方法sayHello。

2、使用new关键字创建实例

javascript 复制代码
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);

person1.sayHello(); // 输出: Hello, my name is Alice and I am 30 years old.
person2.sayHello(); // 输出: Hello, my name is Bob and I am 25 years old.

使用new关键字调用Person构造函数,会创建两个新的Person对象person1和person2,它们分别有自己的name和age属性,以及sayHello方法。

3、只能使用new关键字进行实例化

javascript 复制代码
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayHello = function() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    };
}


function Person1(name, age) {
    if (!(this instanceof Person1)) throw new Error("只能通过new实例化");
    this.name = name;
    this.age = age;
    this.sayHello = function() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    };
}

let p = Person(); //不报错
let p1 = Person1(); //抛出异常

效果图如下所示:

4、构造函数执行过程

创建一个新的空对象。

将这个新对象的__proto__属性指向构造函数的prototype对象。

在新对象的上下文中执行构造函数的代码(即this指向新对象)。

如果构造函数没有显式返回对象,则默认返回新对象。

4.1、prototype属性

每个构造函数都有一个prototype属性,这是一个对象,包含应该由构造函数的所有实例共享的属性和方法。

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

Person.prototype.greet = function() {
    console.log(`Hi, I'm ${this.name}.`);
};

const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);

person1.greet(); // 输出: Hi, I'm Alice.
person2.greet(); // 输出: Hi, I'm Bob.

在构造函数外部,可以通过prototype属性在构造函数的原型链添加新的方法,如上述示例中,使用Person.prototype.greet = function(){} 的形式为Person对象添加了一个新的方法greet。

4.2、this关键字的用途

this是引用当前对象的属性或方法的关键字,在ES6类中,指向的是类的实例。上述每一个示例中都使用到了this关键字。

5、优点和缺点

优点:

  • 构造函数提供了一种方便的方式来创建和初始化对象。
  • 通过prototype可以实现方法和属性的共享,节省内存。

缺点

  • 每个实例上的方法(如果不在prototype上定义)不会共享,会浪费内存。
  • 使用构造函数创建对象相对于使用对象字面量或类(ES6引入)来说,语法上稍显繁琐。

二、工厂函数

在JavaScript中,工厂函数是一种创建对象的模式,它不同于使用构造函数或类的方式。工厂函数是一个普通的函数或者说是一个高阶函数,它返回一个新对象,而不是使用new关键字来实例化对象。这种模式在需要创建多个相似对象时非常有用,尤其是在不需要使用原型链继承或类的复杂结构时。

1、特点

简单性和灵活性

工厂函数是普通的函数,因此它们比使用class或构造函数更简单和灵活。你可以轻松地返回不同类型的对象,或者根据需要添加额外的逻辑来创建对象。

不依赖new 关键字:使用工厂函数时,不需要使用new关键字来创建对象,这减少了错误的可能性(例如忘记使用new)。

无原型链继承的复杂性:工厂函数创建的对象不会自动共享方法或属性通过原型链,这有时可以简化代码,尤其是当不需要这种共享时。

易于理解和使用:工厂函数的代码通常更易于理解和维护,特别是对于不熟悉JavaScript原型链和构造函数的人来说。

2、示例

javascript 复制代码
function createPerson(name, age) {
  return {
    name: name,
    age: age,
    greet: function() {
      console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
  };
}

const alice = createPerson('Alice', 30);
const bob = createPerson('Bob', 25);

alice.greet(); // 输出: Hello, my name is Alice and I am 30 years old.
bob.greet();   // 输出: Hello, my name is Bob and I am 25 years old.

3、工厂函数的优势

  • 语法简洁性 :工厂函数通常比构造函数更简洁,因为它们不需要使用new关键字。
  • 原型链继承:构造函数允许通过原型链共享方法和属性,这在需要节省内存或实现继承时很有用。工厂函数创建的对象不会自动共享这些方法或属性,但你可以通过其他方式(如使用Object.create或手动复制方法)来实现共享。
  • 实例识别 :使用构造函数创建的对象可以通过instanceof操作符识别为特定构造函数的实例。工厂函数创建的对象没有这种内置的实例识别机制。

三、工厂函数与构造函数的比较

工厂函数 构造函数
定义 普通的函数,用于创建并返回一个对象 特殊的函数,用于创建对象,需要使用new关键字
灵活性 高,可以创建不同类型或结构的对象 较低,通常用于创建具有相同结构和行为的对象
代码简洁性 简洁,不需要使用new关键字 复杂,需要使用new关键字,并注意this的指向
实例识别 无法通过instanceof识别对象类型 可以通过instanceof识别对象类型
原型链继承 无法自动通过原型链共享方法和属性 可以通过原型链共享方法和属性
使用场景 适用于需要创建不同类型或结构对象的场景 适用于需要创建具有相同结构和行为对象的场景

四、总结

工厂函数和构造函数都是JavaScript中用于创建对象的常见模式。它们各有特点,适用于不同的场景。选择哪种模式主要取决于项目的具体需求和代码的复杂性。在实际开发中,可以根据需要灵活选择使用哪种模式来创建对象。

相关推荐
利刃大大40 分钟前
【C语言】内存函数详解与模拟实现
c语言·开发语言
顽疲1 小时前
从零用java实现 小红书 springboot vue uniapp (10)系统消息模块 接收推送消息优化
java·vue.js·spring boot·uni-app
siy23331 小时前
[c语言日寄]精英怪:三子棋(tic-tac-toe)3命慢通[附免费源码]
c语言·开发语言·笔记·学习·算法
疯狂的沙粒1 小时前
如何将一个数组转换为字符串?
开发语言·前端·javascript·柔性数组
shix .1 小时前
python范围
开发语言·python
!!!5252 小时前
Mybatis-底层是如何解决sql注入&增删改查操作--删除操作
java·spring boot·mybatis
Lojarro2 小时前
【Vue】Vue组件--上
前端·javascript·vue.js
源之缘-OFD先行者2 小时前
FreeType 介绍及 C# 示例
开发语言·c#
惊鸿一梦q2 小时前
qt5Core.dll是什么文件,qt5Core.dll错误怎么办
开发语言·qt
answerball2 小时前
💥Babel:前端魔法师的炼金术,让你的代码“返老还童”!👴➡️👶
前端·javascript·react.js