使用Object的构造函数可以创建对象或者使用对象字面量来创建单个对象,但是这些方法有一个明显的缺点:使用相同的一个接口创建很多对象,会产生大量的重复代码。
(一)工厂模式

这种模式抽象了创建具体对象的过程。考虑到在ECMAScript中无法创建类,开发人员就开发了一种函数,用函数来封装以特定接口创建对象的细节:

工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别的问题(即怎样知道一个对象的类型)。

(二)构造函数模式

ECMAScript中的构造函数可以用来创建特定类型的对象。像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境中。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。例如,使用构造函数的方法重写上诉问题:

调用构造函数实际是经历如下的过程:
(1)创建一个对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);

(3)执行构造函数中的代码(为新对象添加属性);
(4)返回新对象;

使用这种模式,person1和person2对象分别保存着Person的一个不同的实例。词汇量测试这两个对象都有一个constructor(构造函数)属性,该属性指向Person:

(函数名实际是个指针)

constructor属性最初是用来标识对象类型的。以上创建的两个对象即是Object的实例,同时也是Person(可以
person1 instanceof Person
来进行判断)的实例(因为所有对象都继承自Object),也就是说使用构造函数模式可以将它的实例标识为一种特定的类型,这也是构造函数模式胜过工厂模式的地方。

构造函数与其他函数的唯一区别就是在于它们的调用方式不同。任何函数,只要通过new操作符来调用,那它就可以作为构造函数。同理,前面的Person函数可以通过以下任意一种方式调用:

不使用new操作符的调用,属性和方法都被添加给window对象。
有时构造函数可以这样定义:

从这个角度看,每个Person实例都包含了一个不同的Function实例(以显示name属性)的本质。

然而创建两个完成同样任务的Function实例没有必要,因此可以将函数定义转移到构造函数外:

因此person1和person2对象就共享了在全局作用域中定义的一个sayName()函数。英文地址但是全局作用域中定义的函数只能被某个对象调用,并且如果对象需要定义很多方法,那么就需要多个全局变量函数,即没有了封装性

(三)原型模式

我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,它的用途是包含可以有特定类型的所有实例共享的属性和方法。

prototype就是通过构造函数而创建的那个对象的原型对象。使用原型的好处就是可以让所有对象实例共享它所包含的属性和方法 。

(1)理解原型对象

无论什么时候,只要创建了一个新函数,ECMAScript就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,词汇教学这个属性包含一个指向prototype属性所在函数的指针。就拿前面的例子,Person.prototype.constructor指向Person。而通过这个构造函数,我们还可以继续为原型对象添加其他属性和方法。

创建了自定义指针之后,其原型对象默认只会取得constructor属性;至于其它方法,都会从Object对象继承而来。当调用构造函数创建一个新实例之后,该实例的内部将包括一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个叫[[Prototype]]。

要明确一点的就是,这个连接存在于实例和构造函数的原型对象之间,而不是存在于实例和构造函数之间。

以前面使用的Person构造函数和Person.prototype创建实例的代码为例,如下图:

上图展示了Person构造函数、Person的原型属性以及Person现有的两个实例之间的关系。在此,Person.prototype指向了原型对象,而Person.prototype.constructor又指回了Person。原型对象中除了包含constructor属性之外,香港大学学费还包括后来添加的其他属性。Person的每一个实例——person1和person2都包含一个内部属性,该属性仅仅指向Person.prototype。换句话说,它们与构造函数没有直接的联系。此外,要格外注意的是,虽然这两个实例都不包含属性和方法,但我们却可以调用person1.sayName()。这是通过查找对象属性的过程来实现的。

虽然我们无法访问到[[Prototype]],但可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。从本质上讲,如果[[Prototype]]指向调用isPrototypeOf()方法的对象(Person.prototype),那么这个方法就会返回true。

每当代码要读取某个对象的属性时,都会进行一次搜索,搜索目标是具有给定名称的属性。搜索当然先从对象实例的本身开始,如果找到了,就可以返回该值了;如果找不到,则会去指针所指向的原型对象中去查找,托福和雅思在原型对象中找到了,就可以顺利返回该值。而这正是多个对象实例共享原型所保存的属性和方法的基本原理。

虽然可以通过对象实例访问到保存在原型中的值,但不能通过对象实例重写原型中的值。根据查找原理,如果找到了实例中的值,就不会再去查找原型对象中的值。,代码如下所示:

使用hasOwnPeoperty()方法可以检测一个属性是否存在于实例中,还是存在原型中,这个方法(它是从Object继承来的)只在给定属性存在域对象实例中时,才返回true。

(2)原型与in操作符

有两种方式使用in操作符:一、单独使用;二、for-in中使用。

功能:会在通过对象能够访问给定属性时返回true,无论是在对象实例中或是原型中。

同时使用hasOwnProperty()和in操作符可以判断出该属性到底是存在对象实例中还是存在与原型中。

使用for-in循环时,返回的是所有能够通过对象访问的,可枚举(enumerated)属性,其中即包括存在与实例中的属性,也包括存在与原型中的属性。根据规定,开发人员定义的属性都是可枚举的——IE8及更早版本除。

(3)更简单的原型语法

结果是与先前的相同,但有一个是不同的:contrcutor属性不再指向Person了。我们曾经介绍过,雅思写作教材没创建一个函数,就会同时创建它的prototype对象,这个对象也会自动获得constructor属性。而我们这样写,本质上是完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object构造函数),不再指向Person函数。

当然我可以将它特意设置成适当的值:

以上代码特意包含了一个constructor属性,并将它的值设置为Person,从而确保了通过该属性能够访问到适当的值。

(4)原型的动态性

由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来——即使是先创建了实例后修改原型也照样可以,如下所示:

尽管可以随时为原型添加属性和方法,但如果我们重写了整个原型对象,英语考级那么情况就不一样了。我们知道,调用构造函数时会为实例添加一个指向最初原型的[[Prototype]]指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。一定要记住:实例中的指针仅仅指向原型,而不是构造函数。如下例子:

(6)原型对象的问题

原型模式的最大问题是由其共享的本性所导致的。原型中的所有属性都被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性,通过实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来书,问题便比较突出:

当一个对象想获取独有的操作时,原型模式的共享就是最大的阻碍。因此,目前使用最广泛的是构造函数和原型混成的模式,构造函数模式用于定义实例属性,而原型模式用于定于方法和共享属性。

详细可以参考《Professional JavaScript for Web Developers》3rd Edition

JavaScript之创建对象的模式的更多相关文章

  1. javascript(js)创建对象的模式与继承的几种方式

    1.js创建对象的几种方式 工厂模式 为什么会产生工厂模式,原因是使用同一个接口创建很多对象,会产生大量的重复代码,为了解决这个问题,产生了工厂模式. function createPerson(na ...

  2. 深入理解JavaScript中创建对象模式的演变(原型)

    深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...

  3. JavaScript中创建对象的几种模式

    代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  4. javascript中创建对象的方式总结

    javascript中创建对象的方式总结 具体代码如下: //创建对象的方式: //创建方式一 var person=new Object(); person.name='jack'; person. ...

  5. 浅谈JavaScript中的原型模式

    在JavaScript中创建对象由很多种方式,如工厂模式.构造函数模式.原型模式等: <pre name="code" class="html">/ ...

  6. JavaScript之创建对象

    不定义JQuery插件,不要说会JQuery 一:导言 有些WEB开发者,会引用一个JQuery类库,然后在网页上写一写$("#"),$("."),写了几年就对 ...

  7. javascript中创建对象的几种不同方法

    javascript中创建对象的几种不同方法 方法一:最直白的方式:字面量模式创建 <script> var person={ name:"小明", age:20, s ...

  8. JavaScript对象 创建对象(一)

    创建对象  --以下内容来自JavaScript高级程序设计 工厂模式 用函数来封装以特定接口创建对象的细节. function createPerson(name, age, job){ var o ...

  9. 从ES6重新认识JavaScript设计模式(三): 建造者模式

    1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示. 建造者模式的特点是分步构建一个复杂的对象,可以用不同组合或顺序建造出不 ...

随机推荐

  1. 渗透测试思路 - CTF(番外篇)

    渗透测试思路 ​ Another:影子 (主要记录一下平时渗透的一些小流程和一些小经验) CTF(番外篇) ​ 笔者是一个WEB狗,更多的是做一些WEB类型题目,只能怪笔者太菜,哭~~ 前言 ​ 本篇 ...

  2. mysql orderby limit 翻页数据重复的问题

    在mysql中我们通常会采用limit来进行翻页查询,比如limit(0,10)表示列出第一页的10条数据,limit(10,10)表示列出第二页.但是,当limit遇到order by的时候,可能会 ...

  3. jstack 命令使用经验总结

    jstack 命令的基本使用 jstack 在命令使用上十分简洁, 其信息量与复杂度主要体如今 thread dump 内容的分析上;web # 最基本的使用sudo -u xxx jstack {v ...

  4. rabbitmq消息处理-转载

    目录 1. 消息如何保障百分之百的投递成功? 1.1 方案一:消息落库,对消息状态进行打标 1.2 方案二:消息的延迟投递,做二次确认,回调检查 2. 幂等性 2.1 幂等性是什么? 2.2 消息端幂 ...

  5. LeetCode通关:数组十七连,真是不简单

    分门别类刷算法,坚持,进步! 刷题路线参考:https://github.com/chefyuan/algorithm-base       https://github.com/youngyangy ...

  6. 使用ffmpeg给视频添加跑马灯效果(滚动字幕)

    直接上命令 从左往右滚 ffmpeg -i input.mp4 -vf "drawtext=text=string1 string2 string3 string4 string5 stri ...

  7. GPB重磅!浙大李兰娟院士团队修饰多组学研究揭示炎症反应新机制

    炎症 (inflammation) 是机体对致炎因子的损伤所发生的一种以防御反应为主的基本病理过程.翻译后修饰(PTMs)在调节多种炎症信号通路中起着重要作用,如磷酸化(phosphorylation ...

  8. 代码重构与单元测试——使用“以查询取代临时变量”再次对Statement()方法进行重构(七)

    代码重构与单元测试(一) 代码重构与单元测试--测试项目(二) 代码重构与单元测试--"提取方法"重构(三) 代码重构与单元测试--重构1的单元测试(四) 代码重构与单元测试--对 ...

  9. 记一次在Windows10桌面环境搭建Jekins的吐血经历

    目录 写在前面 故事背景 踩坑详情 最后总结 写在前面 首先声明,除非万不得已,千万不要在Windows环境做这个事情,否则就等着各种坑吧. 本人一贯的立场都是坚持用正确的方法做事,显然在Window ...

  10. 常见的Web攻击手段,拿捏了!

    大家好,我是小菜. 一个希望能够成为 吹着牛X谈架构 的男人!如果你也想成为我想成为的人,不然点个关注做个伴,让小菜不再孤单! 本文主要介绍 互联网中常见的 Web 攻击手段 如有需要,可以参考 如有 ...