使用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. jvm源码解读--10 enum WKID 枚举

    源码中对于枚举类型WKID的使用 static bool initialize_wk_klass(WKID id, int init_opt, TRAPS); static void initiali ...

  2. js精确到指定位数的小数

    将数字四舍五入到指定的小数位数.使用 Math.round() 和模板字面量将数字四舍五入为指定的小数位数. 省略第二个参数 decimals ,数字将被四舍五入到一个整数. const round ...

  3. ifix与AB PLC contrologix 5300系列的通讯

    在最近一个改造项目中,由于先前的4G 平台不稳定,本公司自己组建4G VPN来实现.遇到问题:AB 高版本PLC(1769-L33ER)使用标签名直接代替了地址,ifix的ABR驱动只支持SLC500 ...

  4. 【LeetCode】81. 搜索旋转排序数组 II

    81. 搜索旋转排序数组 II 知识点:数组,二分查找: 题目描述 已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同. 在传递给函数之前,nums 在预先未知的某个下标 k(0 ...

  5. netty系列之:netty中的Channel详解

    目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁,netty中的Ch ...

  6. SQL语句(三)分组函数和分组查询

    目录 一.分组函数 特点 1. 各函数的简单使用 2. 搭配distinct的使用 3. COUNT 统计行数 4. 和分组函数一同查询的字段要求是group by后的字段 二.分组查询 1. 简单应 ...

  7. 心酸!30岁深漂失业3个月,从巅峰跌落谷底,大龄Android开发必须要懂的事!

    2021年3月,我的前同事,在我们群里说他准备回老家了,问我们有没有人可以暂时收养他的猫. --他说,这周末就要离开深圳了. 他失业了.3个多月没收入,还要交着房租,过年来之后找了快一个月的工作也没有 ...

  8. zookeeper查看启动状态报错:Error contacting service. It is probably not running.

    问题描述 我有三台虚拟机master.slave1.slave2.每台虚拟机启动zkServer.sh时都没有报错,然后紧接着查看zkServer.sh的状态,这时候出现了错误:Error conta ...

  9. GO语言安装以及国内镜像

    首先,下载GO语言,国内的话用 Go下载 - Go语言中文网 - Golang中文社区 (studygolang.com) 可能会快一点 然后根据自己的系统选择下载的包,我是win10,就选go1.1 ...

  10. 利用ST-LINK配合ST-LINK Utility 将bin文件下载到STM32的FLASH中

    文章目录 背景 1.连接ST-LINK V2与单片机 2.配置工程 3.配置ST-LINK Utility 4.烧录bin文件 背景 项目需求,要把字模文件导入到32中FLASH的指定地址,使用了ST ...