写在前面

这篇文章讲解创建对象的各种方式,以及优缺点。

但是注意:

这篇文章更像是笔记,因为《JavaScript高级程序设计》写得真是太好了!

1. 工厂模式

function createPerson(name) {var o = new Object(); o.name = name; o.getName = function () { console.log(this.name); }; return o; } var person1 = createPerson('kevin');

缺点:对象无法识别,因为所有的实例都指向一个原型

2. 构造函数模式

function Person(name) {this.name = name; this.getName = function () { console.log(this.name); }; } var person1 = new Person('kevin');

优点:实例可以识别为一个特定的类型

缺点:每次创建实例时,每个方法都要被创建一次

2.1 构造函数模式优化

function Person(name) {this.name = name; this.getName = getName; } function getName() { console.log(this.name); } var person1 = new Person('kevin');

优点:解决了每个方法都要被重新创建的问题

缺点:这叫啥封装……

3. 原型模式

function Person(name) {}Person.prototype.name = 'keivn'; Person.prototype.getName = function () { console.log(this.name); }; var person1 = new Person();

优点:方法不会重新创建

缺点:1. 所有的属性和方法都共享 2. 不能初始化参数

3.1 原型模式优化

function Person(name) {}Person.prototype = { name: 'kevin', getName: function () { console.log(this.name); } }; var person1 = new Person();

优点:封装性好了一点

缺点:重写了原型,丢失了constructor属性

3.2 原型模式优化

function Person(name) {}Person.prototype = { constructor: Person, name: 'kevin', getName: function () { console.log(this.name); } }; var person1 = new Person();

优点:实例可以通过constructor属性找到所属构造函数

缺点:原型模式该有的缺点还是有

4. 组合模式

构造函数模式与原型模式双剑合璧。

function Person(name) {this.name = name; } Person.prototype = { constructor: Person, getName: function () { console.log(this.name); } }; var person1 = new Person();

优点:该共享的共享,该私有的私有,使用最广泛的方式

缺点:有的人就是希望全部都写在一起,即更好的封装性

4.1 动态原型模式

function Person(name) {this.name = name; if (typeof this.getName != "function") { Person.prototype.getName = function () { console.log(this.name); } } } var person1 = new Person();

注意:使用动态原型模式时,不能用对象字面量重写原型

解释下为什么:

function Person(name) {this.name = name; if (typeof this.getName != "function") { Person.prototype = { constructor: Person, getName: function () { console.log(this.name); } } } } var person1 = new Person('kevin'); var person2 = new Person('daisy'); // 报错 并没有该方法 person1.getName(); // 注释掉上面的代码,这句是可以执行的。 person2.getName(); 

为了解释这个问题,假设开始执行var person1 = new Person('kevin')

如果对 new 和 apply 的底层执行过程不是很熟悉,可以阅读底部相关链接中的文章。

我们回顾下 new 的实现步骤:

  1. 首先新建一个对象
  2. 然后将对象的原型指向 Person.prototype
  3. 然后 Person.apply(obj)
  4. 返回这个对象

注意这个时候,回顾下 apply 的实现步骤,会执行 obj.Person 方法,这个时候就会执行 if 语句里的内容,注意构造函数的 prototype 属性指向了实例的原型,使用字面量方式直接覆盖 Person.prototype,并不会更改实例的原型的值,person1 依然是指向了以前的原型,而不是 Person.prototype。而之前的原型是没有 getName 方法的,所以就报错了!

如果你就是想用字面量方式写代码,可以尝试下这种:

function Person(name) {this.name = name; if (typeof this.getName != "function") { Person.prototype = { constructor: Person, getName: function () { console.log(this.name); } } return new Person(name); } } var person1 = new Person('kevin'); var person2 = new Person('daisy'); person1.getName(); // kevin person2.getName(); // daisy 

5.1 寄生构造函数模式

function Person(name) {var o = new Object(); o.name = name; o.getName = function () { console.log(this.name); }; return o; } var person1 = new Person('kevin'); console.log(person1 instanceof Person) // false console.log(person1 instanceof Object) // true

寄生构造函数模式,我个人认为应该这样读:

寄生-构造函数-模式,也就是说寄生在构造函数的一种方法。

也就是说打着构造函数的幌子挂羊头卖狗肉,你看创建的实例使用 instanceof 都无法指向构造函数!

这样方法可以在特殊情况下使用。比如我们想创建一个具有额外方法的特殊数组,但是又不想直接修改Array构造函数,我们可以这样写:

function SpecialArray() {var values = new Array(); for (var i = 0, len = arguments.length; i < len; i++) { values.push(arguments[i]); } values.toPipedString = function () { return this.join("|"); }; return values; } var colors = new SpecialArray('red', 'blue', 'green'); var colors2 = SpecialArray('red2', 'blue2', 'green2'); console.log(colors); console.log(colors.toPipedString()); // red|blue|green console.log(colors2); console.log(colors2.toPipedString()); // red2|blue2|green2

你会发现,其实所谓的寄生构造函数模式就是比工厂模式在创建对象的时候,多使用了一个new,实际上两者的结果是一样的。

但是作者可能是希望能像使用普通 Array 一样使用 SpecialArray,虽然把 SpecialArray 当成函数也一样能用,但是这并不是作者的本意,也变得不优雅。

在可以使用其他模式的情况下,不要使用这种模式。

但是值得一提的是,上面例子中的循环:

for (var i = 0, len = arguments.length; i < len; i++) { values.push(arguments[i]); }

可以替换成:

values.push.apply(values, arguments);

5.2 稳妥构造函数模式

function person(name){var o = new Object(); o.sayName = function(){ console.log(name); }; return o; } var person1 = person('kevin'); person1.sayName(); // kevin person1.name = "daisy"; person1.sayName(); // kevin console.log(person1.name); // daisy 

所谓稳妥对象,指的是没有公共属性,而且其方法也不引用 this 的对象。

与寄生构造函数模式有两点不同:

  1. 新创建的实例方法不引用 this
  2. 不使用 new 操作符调用构造函数

稳妥对象最适合在一些安全的环境中。

稳妥构造函数模式也跟工厂模式一样,无法识别对象所属类型。

转载于:https://www.cnblogs.com/guaidianqiao/p/7762233.html

创建对象的多种方式以及优缺点相关推荐

  1. JavaScript继承的多种方式和优缺点

    1.原型链继承 function Parent () {this.name = '张三'; }Parent.prototype.getName = function () {console.log(t ...

  2. Spring学习总结(一)——Spring实现IoC的多种方式

    一.Spring框架概述 Spring是一个开源免费的框架,为了解决企业应用开发的复杂性而创建.Spring框架是一个轻量级的解决方案,可以一站式地构建企业级应用.Spring是模块化的,所以可以只使 ...

  3. 采用策略模式实现订单支付多种方式

    背景 项目中订单支付为常见的功能,一般的订单支付都会包含多种方式,例如聚合支付.会员支付.积分支付的等多种方式,如果采用传统的方式来实现,需要使用多个if/else条件判断,本文将介绍如何采用策略+工 ...

  4. C#IO之导入导出Excel的多种方式

    C#IO之导入导出Excel的多种方式 一.基本介绍: 今天给大家带来的是Excel导入导出的多种实现方式,以及他们的各自的优势以及劣势,首先第一种方式是使用Office组件的方式 ,第二种方式是使用 ...

  5. JS遍历数组的多种方式

    JS遍历数组的多种方式 1. 普通for循环 for (let i = 0; i < arr.length; i++){//code} 应用最为普遍的循环写法,性能好,可读性好. 2. 优化版f ...

  6. JavaScript中的几种继承方式及优缺点,你知道多少呢?

    原文连接:JavaScript中的几种继承方式及优缺点,你知道多少呢? 继承也是前端里面的重要的一个知识点,在实际工作中或者面试中也会经常的遇到,那么通过这篇文章我们详细的了解一下继承的几种方式以及各 ...

  7. python做定时任务的方式及优缺点_python BlockingScheduler定时任务及其他方式的实现...

    本文介绍了python BlockingScheduler定时任务及其他方式的实现,具体如下: #BlockingScheduler定时任务 from apscheduler.schedulers.b ...

  8. java设计模式中不属于创建型模式_23种设计模式第二篇:java工厂模式定义:工厂模式是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式...

    23种设计模式第二篇:java工厂模式 定义: 工厂模式是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 工厂模式主要是为创建对象提供过渡接口, ...

  9. C++多线程:thread类创建线程的多种方式

    文章目录 描述 函数成员简介 总结 描述 头文件 <thread> 声明方式:std::thread <obj> 简介 线程在构造关联的线程对象时立即开始执行,从提供给作为构造 ...

最新文章

  1. 关于运维体系谈谈我的想法
  2. scheduledexecutorservice 的使用_使用J.U.C实现定时任务
  3. 启动celery后执行任务报错:django.core.exceptions.ImproperlyConfigured
  4. echarts3 graph java_Echarts中graph类型的运用求教
  5. android中将自己的自定义组件打成JAR包
  6. oauth2.0 学习案例demo_Vue3教程:用 Vue3 开发小程序,这里有一份实际的代码案例!...
  7. Zabbix监控nginx status
  8. 利用navicat for mysql实现mysql数据库表结构复制
  9. 20200728:力扣199周周赛题解(上)
  10. FIN7 正在转向密码重置和软件供应链攻击
  11. FlashDevelop 3.0.0 Beta2 released
  12. html实现横向轮播,js实现横向轮播效果
  13. stretchblt 模糊_微软开源持续开发模糊测试工具OneFuzz
  14. 2020Java学习路线(珍藏版)
  15. Java底层--JVM与GC
  16. 最强大脑记忆曲线(7)——“复习页面”逻辑实现
  17. 异步传输模式 (ATM)
  18. SAD SATD的区别及应用
  19. python格式和JSON格式转换
  20. elasticsearch的使用

热门文章

  1. filter过滤器_不了解布隆过滤器?一文给你整的明明白白
  2. mysql 动态创建事件_mysql 通过事件定时为数据库创建动态表名
  3. java 有序map_Java有序的Hash集合:LinkedHashMap
  4. python3.7 安装pip3_安装python3.7 pip3.7 去哪里了?
  5. 互联网+大赛作品_【快讯】智物联获第二届中国工业互联网大赛优秀作品奖
  6. java helper 设计模式_必知必会的 Java 设计模式入门知识(十):外观模式
  7. java 支付类的接口,Java后端支付大杂烩之core.dao,service,web(重点是接口的设计)(二)...
  8. vue element container 子路由
  9. Spring mvc @PathVaribale
  10. BS4 find_all