JavaScript中创建对象的几种模式(原型)--源自技术

本文介绍了JavaScript中创建对象的六种模式:对象字面量、工厂模式、构造函数模式、原型模式、组合构造函数和原型模式及动态原型模式,并详细探讨了每种模式的特点及其应用场景。

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

**JavaScript创建对象模式:

  • 对象字面量
  • 工厂模式
  • 构造函数模式
  • 原型模式
  • 结合构造函数和原型模式
  • 原型动态模式 
    ** 
    面向对象的语言大都有一个类的概念,通过类可以创建多个具有相同方法和属性的对象。虽然从技术上讲,javascript是一门面向对象的语言,但是javascript没有类的概念,一切都是对象。任意一个对象都是某种引用类型的实例,都是通过已有的引用类型创建;引用类型可以是原生的,也可以是自定义的。

1、对象字面量

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> person = {
        name : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Nicholas'</span>;
        age : <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'22'</span>;
        job :<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"software Engineer"</span>
        sayName: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
            alter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.name);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
例子中创建一个名为person的对象,并为它添加了三个属性(name,age,job)和一个方法(sayName()),其中,sayName()方法用于显示this.name(被解析为person.name)的值。

对象字面量可以用来创建单个对象,但这个方法有个明显的缺点:使用同一个接口创建很多对象,会产生大量重复的代码。

2、工厂模式 
工厂模式是软件工程领域中一种广为人知的设计模式,工厂模式抽象了创建具体对象的过程,用函数来封装以特定的接口创建对象的细节。

function createPerson(name,age,job){
    var o = new object{};
    o.name=name;
    o.age=age;
    o.job=job;
    o.sayName=function(){
        alert(this.name);
    };
    return o;
}

var person1=creatPerson("Nicholas",22,"software Engineer");
var person2=creatPerson("Greg",24,"student");
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
函数creatPerson{}能够根据接受的参数构建一个包含所有必要信息的Person对象。可以无数次的调用这个函数,每次都会返回一个包含三个属性一个方法的对象。

工厂模型虽然解决了创建多个相似对象的问题,却没有解决对象识别的问题(即怎么知道一个对象的类型)。 
3、构造函数模式

function Person(name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        alert(this.name);
    }
}
//通过new操作符创建Person的实例
var person1 = new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.sayName(); //Nicholas
person2.sayName(); //Greg
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

与工厂模式不同的是

  • 没有显示的创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句

创建Person的新实例,必须使用new操作符。调用构造函数的4个步骤:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(this指向了这个新对象)
  • 执行构造函数中的代码
  • 返回新对象

这个例子中创建的所有对象既是Object的实例,也是Person实例。可以通过instanceof操作符验证。

alert(person1 instanceof Object);//true
alert(person1 instanceof Person);//true
 
 
  • 1
  • 2

构造函数模式也有自己的问题,实际上,sayName方法在每个实例上都会被重新创建一次,需要注意的是,通过实例化创建的方法并不相等,以下代码可以证明 
alert(person1.sayName == person2.sayName);//false 
可以将方法移到构造器的外部作为全局函数来解决这个问题。

function Person(name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;   
}
function sayName() {
        alert(this.name);
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在全局下创建的全局函数实际上只能被经由Person创建的实例调用,这就有点名不副实了;如果对象需要定义很对方法,那么就要定义很多个全局函数,缺少封装性。 
4、原型模式 
JavaScript中创建的每个函数都有一个prototype(原型)属性,它是一个指针,指向一个对象,包含了可以由特定类型的所有实例共享的属性和方法(让所有的对象实例共享它的属性和方法)

function Person() {}
   Person.prototype.name ="Nicholas";
   Person.prototype.age = 22;
   Person.prototype.job = "software Engineer";   
   Person.prototype.sayName(){
       alert(this.name);
   };
 var person1 = new Person();
 person1.sayName(); //Nicholas
alert(person1.sayName == person2.sayName);//true
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

以上代码做了这几件事情:

  • 定义了一个构造函数Person,Person函数自动获得一个prototype属性,该属性默认只包含一个指向Person的constructor属性
  • 通过Person.prototype添加三个属性,和一个方法
  • 创建一个Person的实例,随后在实例上调用了sayName()方法 
    使用Person构造函数和Person.prototype创建实例的代码为例,展示个对象之间的关系 
    使用Person构造函数和Person.prototype创建实例的代码为例,展示个对象之间的关系 
    图中展示了Person构造函数、Person的原型属性以及Person的两个实例,之间的关系。Person.prototype指向了原型对象,Person.prototype.constructor有指回了Person。原型对象中除了包含constructor属性,还包含后来添加的其他属性和方法,Person的两个实例person1和person2都包含一个内部属性,该属性仅指向Person.prototype。 
    sayName()方法的调用过程
  • 在person1实例上查找logName()方法,发现没有这个方法,于是追溯到person1的原型
  • 在person1的原型上查找sayame()方法,有这个方法,于是调用该方法

    基于这样一个查找过程,我们可以通过在实例上定义原型中的同名属性,来阻止该实例访问原型上的同名属性,需要注意的是,这样做并不会删除原型上的同名属性,仅仅是阻止实例访问。

function Person() {}
   Person.prototype.name ="Nicholas";
   Person.prototype.age = 22;
   Person.prototype.job = "software Engineer";   
   Person.prototype.sayName(){
       alert(this.name);
   };
 var person1 = new Person();
 var person2 = new Person();
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
alert(person2.name) //Nicholas 来自原型
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

使用delete操作符可以完全删除实例属性

delete person1.name;
alert(person1.name) //Nicholas 来自原型
 
 
  • 1
  • 2

使用hasOwnProperty()方法可以检测一个属性是存在于实例还是原型中

function Person() {}
   Person.prototype.name ="Nicholas";
   Person.prototype.age = 22;
   Person.prototype.job = "software Engineer";   
   Person.prototype.sayName(){
       alert(this.name);
   };
 var person1 = new Person();
 var person2 = new Person();
 alert(person1,hasOwnProperty("name"));//false
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
 alert(person1,hasOwnProperty("name"));//true
alert(person2.name) //Nicholas 来自原型
 alert(person2,hasOwnProperty("name"));//false
 delete person1.name;
alert(person1.name) //Nicholas 来自原型
 alert(person1,hasOwnProperty("name"));//false
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下图展示了在不同情况下实例与原型之间的关系这里写图片描述

简单的原型语法

function Person() {}
 Person.prototype={
  name :"Nicholas",
  age : 22,
  job : "software Engineer",  
  sayName:function(){
       alert(this.name);
       }
   };
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在上面的代码中constructor属性不再指向Person了,通过constructor无法确定对象的类型了。可以像下面这样特意将他设置回适当的值

function Person() {}
 Person.prototype={
 constructor:Person,
  name :"Nicholas",
  age : 22,
  job : "software Engineer",   
  sayName:function(){
       alert(this.name);
       }
   };
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

重设constructor属性会导致它的[[Enumerable]]特性被设置为true,默认情况,原生的constructor属性是不可枚举的,可以使用Object.defineProperty()方法来改变

Object.defineProperty(Person.prototype,"constructor",{
    enumerable:false,
    value:Person
});
 
 
  • 1
  • 2
  • 3
  • 4

原型中查找值的过程是一次搜索,原型对象所做的任何修改都能从实例上立即反应出来

var friend=new Person();
Person.prototype.sayHi=function(){
    alert("hi);
}
friend,sayHi();//"hi"(没有问题)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

person实例是在添加新方法之前创建的,但仍可以访问新添加的方法,原因是实例与原型之间的松散连接关系 
重写原型对象后的情况

function Person() {}
var friend=new Person();
 Person.prototype={
  name :"Nicholas",
  age : 22,
  job : "software Engineer",  
  sayName:function(){
       alert(this.name);
       }
   };
   friend.sayName();//error
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

调用friend.sayName()时发生错误的原因是,friend指向的原型中不包含以该字段命名的属性,如下图。 
这里写图片描述 
原型对象的问题 
原型对象省略了为构造函数传递初始化参数这一环节,所有势力在默认情况下都取得相同的属性值。原型模型最大的问题是有其共享本性所导致的。当原型模型包含引用类型的属性来说,问题就比较严重了。来看下面的例子。

function Person() {}
 Person.prototype={
 constructor:Person,
  name :"Nicholas",
  age : 22,
  job : "software Engineer",   
  friends:["Shelby","Court"],
  sayName:function(){
       alert(this.name);
       }
   };
   var person1=new Person();
   var person2=new Person();
   person1.friend.push("Van");
   alert(person1.friends);//"Shelby,Court,Van"
   alert(person2.friends);//"Shelby,Court,Van"
 alert(person1.friends==person2.friends);//true
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5、组合使用构造函数模式和原型模式 
组合使用构造函数模式和原型模式中,构造函数用于定义实例属性,原型模型用于定义方法和共享的属性。这样每个实例都会有自己的一份实例属性的副本,同时也可以共享对方法的引用,最大限度的节省了内存。

function Person(name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;   
    this.friends=["Shelby","Court"];
}
Person.prototype={
  constructor:Person,
  sayName:function(){
       alert(this.name);
       }
   }
var person1=new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.friend.push("Van");
   alert(person1.friends);//"Shelby,Court,Van"
   alert(person2.friends);//"Shelby,Court"
 alert(person1.friends==person2.friends);//false
 alert(person1.sayName==person2.sayName);//true
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

6、动态原型模式 
原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

function Person(name,age) {
    this.name = name;
    this.age = age;
    this.job =job;
//方法
    if(typeof this.sayName != 'function') {
    Person.prototype.sayName = function() {
           alert(this.name);
        };      
    }
}

var friend = new Person('Nicholas','22','Software Engineer');//初次调用构造函数,此时修改了原型
var person2 = new Person('amy','21');//此时sayName()方法已经存在,不会再修改原型
<think>嗯,我现在要回答用户关于“3216封装钽电容16v全名”的问题。首先,我需要确认用户的问题具体指的是什么。看起来用户想知道这种钽电容的完整名称,可能包括封装尺寸、电压额定值以及其他相关参数。 首先,我应该回忆一下钽电容的基本知识。钽电容通常以它们的封装尺寸、电压、容值等参数来命名。常见的封装类如3216,这应该是指尺寸代码,但需要确认是否正确。钽电容的封装代码通常采用EIA标准,比如3216对应的是EIA的尺寸代码,转换成毫米的话,3216可能代表3.2mm×1.6mm的尺寸,但有时候可能有不同的表示方式,比如另一种命名方式中的“A”或“B”封装,不过可能需要进一步核实。 接下来,电压16V应该是额定电压,也就是电容器能承受的最大电压。钽电容的电压等级通常有多个,比如6.3V、10V、16V、25V等,所以16V是一个常见的规格。 然后,全名可能包括品牌、系列、容值、公差、封装、电压等。例如,一个完整的号可能是像KEMET的T491系列,或者其他制造商的类似产品。例如,T491B106K016AT,其中各部分可能代表:T491是系列,B是封装代码,106是容值(10µF),K是公差(±10%),016是电压(16V),A可能代表包装方式,T是包装形式。 不过用户可能不需要具体的品牌号,而是通用的命名方式。因此,全名可能包括封装尺寸(3216)、结构(钽电容)、电压(16V),以及其他参数如容值和公差,但用户问题中未提到容值,所以可能需要解释这些部分如何构成全名。 另外,需要注意的是,3216封装可能对应不同的代码,比如EIA的3216-18(3.2mm×1.6mm),而有时候也被称为“B”封装,例如在AVX的钽电容中,3216封装对应的是B case。因此,全名可能包括封装代码,如“3216 (B)封装”。 总结一下,全名可能结构为:封装尺寸(3216,即EIA 3216-18或B)+ 钽电容(固体钽电解电容器)+ 额定电压(16V)+ 其他参数如容值和公差(但用户未提供,所以可能需要指出这些参数通常存在)。 需要确认是否3216封装对应正确的尺寸,避免混淆。例如,3216可能有两种解释:一种是EIA的3216(3.2mm×1.6mm),另一种是公制尺寸,但通常钽电容的封装代码如A、B、C对应不同尺寸。例如,AVX的B是3.5mm×2.8mm,而可能3216是另一种标准,或者用户可能误用了封装代码。不过,常见的钽电容封装代码如A、B、C、D等,例如,B对应EIA 3528-21(3.5mm×2.8mm),这可能意味着用户提到的3216可能不是标准钽电容封装代码,或者可能存在不同厂家的命名差异。 因此,可能需要指出,3216封装可能是指尺寸代码,但不同制造商可能有不同的命名方式,所以需要确认具体的制造商号。例如,某些厂家可能将3216作为封装代码,而其他厂家可能使用不同的代码。在这种情况下,全名可能包括制造商的系列名称、封装代码、电压、容值等,但用户只提供了封装和电压,所以可能需要一般性的解释,并建议用户查阅具体的数据手册以获取完整号。 另外,钽电容的全名可能还包括极性(钽电容是有极性的)、材料(固体或液体电解质,这里应该是固体钽电容),以及是否符合特定标准,如AEC-Q200用于汽车应用等,但可能用户不需要这些细节。 综上所述,用户的问题可能需要拆解为几个部分:封装、类、电压,然后解释各部分的意义,并指出完整的号通常还包括容值、公差、系列等,但基于用户提供的信息,只能给出部分名称,并建议补充其他参数以获得准确号。</think>关于“3216封装钽电容16V”的全名,以下是逐步解析: --- ### **1. 基本定义** 这是一种**表面贴装固体钽电解电容器**,其核心特征包括: - **封装尺寸**:3216(公制代码,对应3.2mm×1.6mm的尺寸)。 - **额定电压**:16V。 - **极性**:有极性(需注意正负极方向)。 --- ### **2. 全名组成** 完整名称通常包含以下参数(以通用格式为例): ``` [封装代码]-[电容类]-[额定电压]-[电容值]-[公差]-[附加代码] ``` 例如: $$ \text{3216B-TANT-16V-10µF-K} $$ - **3216**:封装尺寸(3.2mm×1.6mm)。 - **B**:封装类(部分厂商用字母表示,如B对应3216)。 - **TANT**:钽电容标识。 - **16V**:额定电压。 - **10µF**:电容值(需根据具体号填写)。 - **K**:公差(如K=±10%)。 --- ### **3. 关键参数说明** - **封装代码**: - 3216是**公制尺寸**,对应英制代码为**1206**(长×宽:0.12英寸×0.06英寸)。 - 部分厂商可能用字母表示(如AVX的B封装对应3.5mm×2.8mm,需注意区分)。 - **电压与容值**: - 16V为**额定电压**,实际使用需降额(通常按50%~80%设计)。 - 容值(如10µF、22µF)需根据具体号确定。 --- ### **4. 典号示例** 以厂商**KEMET**或**AVX**的号为例: - **KEMET T491B106K016AT**: - T491:系列名称(低ESR固体钽电容)。 - B:封装代码(对应3216尺寸)。 - 106:容值(10×10⁶ pF = 10µF)。 - K:公差(±10%)。 - 016:额定电压(16V)。 - A:包装形式(卷带包装)。 --- ### **5. 注意事项** - **封装混淆**:3216可能与其他标准冲突(如贴片电阻的3216封装),需通过“钽电容”标识区分。 - **选建议**:需结合**容值、耐压、ESR、纹波电流**等参数,并参考厂商手册。 --- ### **总结** 用户提到的“3216封装钽电容16V”全名需补充具体参数(如容值、公差)才能确定唯一号。通用名称可描述为: **3216封装(3.2mm×1.6mm)表面贴装固体钽电解电容器,额定电压16V**。 建议提供更多参数或查阅厂商手册以获取完整号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值