js工厂模式、构造函数以及他们创建对象的优缺点? — 第6.2.1节

本文对比了JavaScript中的工厂模式和构造函数模式,探讨了它们的优缺点,并讲解了如何使用构造函数创建对象实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工厂模式和构造函数的区别

学习JavaScript有一段时间了,但是随着工作的进展,我发现,JavaScript绝对不是写一下简单效果那么肤浅,是时候完全,透彻地理解他的精髓了。

好了,让俺老猪带你装逼带你飞吧!
一:
为什么使用工厂模式和构造函数?
  虽然Object构造函数或者字面量(var person={})可以创建单个对象,但是,他有一个明显的缺点,那就是:重复造轮子,产生大量的重复性代码,为了解决这个问题,我们就开始使用工厂模式和构造函数模式。
二:
什么是工厂模式?它有什么优缺点?
  1.顾名思义,工厂模式就是像工厂一样来创建对象。但这样的解释似乎有点欠妥,高大上一点,工厂模式其实是软件领域中一种广为人知的一种设计模式,这种模式抽象了创建具体对象的过程。开发人员发明了一种函数,用函数来大量创建对象的方法;
2.工厂模式例子如下:

function createPerson(name,age,say){
    var obj1 = new Object();
    obj1.name = name;
    obj.age = age;
    obj.say = say;
    obj.should = function(){
        alert(this.say);
    }
    return obj;
}
var person1 = createPerson('bangbang',18,'脚踏实地才能壮志凌云!');
var person2 = createPerson('yanniu',18,'我相信你可以!');

  但是工厂模式可以创建多个相似的对象,但是却没有解决对象的识别问题(不知道这个对象的类型)。相信这句话还需要探究,不要急,接下来看那看构造函数模式,你就会理解。
三:
什么是构造函数模式,它和工厂模式比较有哪些好处?它自身又有那些缺点?
  1.实例如下:

function CreatePerson(name, age, say){
    this.name = name;
    this.age = age;
    this.say = say;
    this.should = function(){
        console(this.say);
    }
}
var person1 = new CreatePerson('bangbang',18,'修身,齐家,天下很太平');
var person2 = new CreatePerson('yanniu',18,'吃地沟油的命,操中南海的心');

  这个例子中,CreatePerson()函数取代了createPerson()函数;睁大你的两个招子,第二个CreatePerson()明显是开头大写,这是构造函数的惯例,为了区分和普通函数的区别,因为构造函数也是函数,只不过可以创建对象而已。和工厂模式不同之处看最后一点,不要着急,先自己感悟一下,先说出来就没有味道了,嘿嘿!
2.要创建CreatePerson()的新实例,必须使用new,即和使用var person1 = new Object()差不多,实际上会经历一些步骤:

  • 创建一个新的对象;
  • 将构造函数作用域赋给新的对象(即this指向新对象);
  • 执行构造函数里面的代码;
  • 返回新的对象。
    但是创建的person1和person2都有一个constructor(构造函数)属性,该属性指向CreatePerson,代码如下:
console.log(person1.constructor == CreatePerson());//true
console.log(person2.constructor == CreatePerson());//true

  不过用instanceof操作符来检测对象的类型还是更可靠地,因为instanceof是用来专门比较一个对象是否为某个构造函数的实例。

console.log(person1 instanceof Object);      //true;
console.log(person1 instanceof CreatePerson);//true;
console.log(person2 instanceof Object);      //true;
console.log(person2 instanceof CreatePerson);//true;

  创建自定义的构造函数意味着将来可以将他的实例标识为一种特定的类型,这就是构造函数比工厂模式强的地方,因为它只道自己从哪里来,通过谁产生的,在回顾上面(一)我所写的,你就会很明白了。
四:
构造函数和普通函数的区别在哪?
  1.构造函数和普通函数唯一的区别是他们的调用方式不同。
  2.任何函数只要通过new来调用,那它就可以作为构造函数,而任何函数,如果不通过new操作符来调用,他就是普通的函数。
  例子如下:

//当做构造函数来使用
var person1 = new CreatePerson('bangbang',18,'修身,齐家,天下很太平');
person1.should(); //'修身,齐家,天下很太平'

//构造函数当做普通函数使用
CreatePerson('bangbang',18,'修身,齐家,天下很太平')
window.should();//'修身,齐家,天下很太平'
//在另一个对象的作用域中调用(这个需要以后的继承探讨)
var  person3 = new Object():
CreatePerson.call(person3,'qiqi',18,'我是一个护士');//person3就有了CreatePerson类的所有的属性和should方法

五:
构造函数有哪些不足之处?
  1.构造函数最明显的缺点就是,每个方法都要在每个实例上重新创建一遍。在前面的例子中,person1和person2都有一个should的方法,但是两个方法不是同一个Function的实例,因此每定义一个函数(也就是实例化一个对象),从逻辑上构造函数还可以这样定义:

function CreatePerson(name,age,say){
    this.name = name;
    this.age = age;
    this.say = say;
    this.should = new Function('console.log(this.say)');
}

  由上面可以得出这种方式创建函数实例化出的对象都包含一个不同的Function实例,说的更通俗点:这种方式创建函数,会导致不同的作用域链和标识符解析,但是创建Function的新实例的机制仍然是相同的。所以,不同实例上的同名函数是不相等的,证明如下:

console.log(person1.should == person2.should);//false

2.因此以上的写法可以这样简化:

function CreatePerson(name,age,say){
    this.name = name;
    this.age = age;
    this.say = say;
    this.should = should;
}
function should(){
    console.log(this.say);
}
var person1 = new CreatePerson('bangbang',18,'乐观');
var person2 = new CreatePerson('yanniu',18,'切记盲目乐观');

  我们把函数放在构造函数的外面作为全局函数,因此person1和person2对象就共享了在全局作用域中定义的同一个say函数。但是问题又来了:在全局作用域中定义的函数实际上只能被某个对象调用,这让该全局作用域有点名不副实。,更让然无法接受的是:如果对象需要定义很多方法,那么就要定义很多个全局函数,那么我们这个自定义的引用类型就丝毫没有封装性可言了。因此我们需要另一种高大上的模式,——原型模式(prototype)。

<think>我们正在讨论JavaScript工厂模式构造函数创建对象的本质区别。根据引用内容,我们可以总结如下: 1. **工厂模式**: - 通过一个工厂函数封装对象的创建过程,函数内部显式创建对象(如`new Object()`),设置属性方法,最后返回该对象。 - 每次调用工厂函数都会创建一个新对象,但无法解决对象类型识别问题(即创建的所有对象都是`Object`类型,无法识别为特定类型)。 2. **构造函数模式**: - 使用自定义构造函数函数名通常首字母大写),通过`new`操作符调用。 - 构造函数内部使用`this`来添加属性方法,没有显式创建对象返回对象(由`new`操作符自动完成)。 - 创建的对象实例可以标识为特定类型(即实例的`constructor`属性指向构造函数,且可以通过`instanceof`检测类型)。 ### 本质区别总结: | **区别点** | **工厂模式** | **构造函数模式** | |--------------------|---------------------------------------------|-------------------------------------------| | **对象创建方式** | 显式创建对象(如`new Object()`)并返回 | 由`new`操作符隐式创建对象,无需显式返回 | | **对象类型识别** | 所有对象都是`Object`类型,无法识别具体类型 | 对象实例标识为构造函数类型(如`Person`) | | **内部属性指向** | 无特殊内部属性指向工厂函数 | 实例的`constructor`属性指向构造函数 | | **`this`的指向** | 在工厂函数内部,`this`指向不固定(可能全局)| 构造函数内`this`指向新创建的实例 | | **内存占用** | 方法在每次创建时都生成新函数(占用更多内存)| 同样存在方法重复创建问题(可结合原型解决)| ### 代码示例对比: #### 工厂模式: ```javascript function createPerson(name, age) { var o = new Object(); // 显式创建对象 o.name = name; o.age = age; o.sayName = function() { console.log(this.name); }; return o; // 显式返回对象 } const p1 = createPerson("Alice", 25); console.log(p1 instanceof Object); // true console.log(p1.constructor); // [Function: Object] (无法识别为Person) ``` #### 构造函数模式: ```javascript function Person(name, age) { // 隐式创建对象: this = new Object() this.name = name; this.age = age; this.sayName = function() { console.log(this.name); }; // 隐式返回: return this; } const p2 = new Person("Bob", 30); console.log(p2 instanceof Person); // true (可识别类型) console.log(p2.constructor); // [Function: Person] ``` ### 关键区别解析: 1. **类型识别**:构造函数模式创建的对象具有明确的类型标识(通过`instanceof``constructor`属性),而工厂模式创建的对象均为`Object`类型[^3][^4]。 2. **创建机制**:构造函数依赖`new`操作符自动完成对象创建返回,工厂模式需手动创建返回对象。 3. **设计意图**: - 工厂模式是抽象创建过程的设计模式,适用于需要灵活控制对象创建的场合。 - 构造函数模式JavaScript模拟面向对象类的机制,强调类型标识实例关系。 > 最佳实践:若需要类型识别继承特性,优先使用构造函数模式(或ES6 Class);若仅需简单封装创建过程,工厂模式更轻量[^3][^4]。 §§相关问题§§ 1. 如何用工厂模式实现跨浏览器的自定义弹窗组件? 2. 构造函数模式中如何优化方法重复创建的问题? 3. JavaScript的`new`操作符底层具体执行了哪些步骤? 4. ES6 Class语法与构造函数模式有何关联? 5. 在什么场景下工厂模式构造函数模式更适用?</think>### JavaScript 工厂模式构造函数创建对象的本质区别 #### 1. **核心目的差异** - **工厂模式**:抽象对象创建过程,**关注对象创建本身** 通过函数封装创建逻辑,隐藏实例化细,返回新对象(通常是普通 Object)[^2][^5] ```javascript function createPerson(name) { const obj = new Object(); // 显式创建对象 obj.name = name; obj.sayName = function() { console.log(this.name) }; return obj; // 显式返回对象 } ``` - **构造函数模式**:**定义对象类型标识** 通过 `new` 操作符创建特定类型的实例,隐含创建返回对象[^3][^4] ```javascript function Person(name) { // 隐含创建:this = new Object() this.name = name; this.sayName = function() { console.log(this.name) }; // 隐含返回:return this } ``` #### 2. **对象类型识别(关键区别)** | **模式** | `instanceof` 检测 | `constructor` 属性 | 类型标识能力 | |----------------|--------------------------|--------------------------|--------------| | 工厂模式 | `obj instanceof Object` ✅ | 指向 `Object` | ❌ 无类型标识 | | 构造函数模式 | `obj instanceof Person` ✅ | 指向构造函数 `Person` | ✅ 强类型标识 | **示例验证**: ```javascript // 工厂模式 const factoryObj = createPerson("Alice"); console.log(factoryObj instanceof Object); // true console.log(factoryObj instanceof createPerson); // false ❌ 无法识别工厂函数 // 构造函数模式 const constructorObj = new Person("Bob"); console.log(constructorObj instanceof Person); // true ✅ 识别为Person类型 console.log(constructorObj.constructor === Person); // true ``` #### 3. **创建机制差异** | **特性** | 工厂模式 | 构造函数模式 | |------------------|---------------------------|---------------------------| | 对象创建 | 显式 `new Object()` | 隐式通过 `new` 操作符创建 | | 返回值 | 必须显式 `return` 对象 | 自动返回 `this` | | `this` 指向 | 指向新创建的对象 | 指向新实例 | | 命名规范 | 驼峰命名(如 createXxx) | 首字母大写(如 Person) | #### 4. **内存占用问题** - **共同缺陷**:两种模式都会**为每个对象创建独立的方法副本** ```javascript const p1 = new Person("Tom"); const p2 = new Person("Jerry"); console.log(p1.sayName === p2.sayName); // false ❌ 方法重复创建 ``` - **解决方案**:结合原型模式共享方法 ```javascript function Person(name) { this.name = name; } // 方法定义在原型上 Person.prototype.sayName = function() { console.log(this.name) }; ``` #### 5. **适用场景对比** - **工厂模式适用**: - 需要创建多种异构对象 - 不关心对象具体类型 - 跨环境对象创建(如浏览器兼容性处理) - **构造函数模式适用**: - 需要明确对象类型标识 - 实现基于原型的继承链 - 与 `instanceof` 类型检测配合使用 > **本质总结**:工厂模式是**创建过程抽象**,构造函数模式是**类型定义机制**。前者解决"如何创建",后者解决"创建什么"并建立类型标识[^3][^4]。 --- ### 相关问题 1. 如何用工厂模式实现跨浏览器的自定义弹窗组件? 2. 构造函数模式中如何优化方法重复创建的问题? 3. JavaScript 的 `new` 操作符底层具体执行了哪些步骤? 4. ES6 Class 语法与构造函数模式有何关联? 5. 在什么场景下工厂模式构造函数模式更适用?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值