创建对象的多种方式以及优缺点
写在前面
这篇文章讲解创建对象的各种方式,以及优缺点。
但是注意:
这篇文章更像是笔记,因为《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 的实现步骤:
- 首先新建一个对象
- 然后将对象的原型指向 Person.prototype
- 然后 Person.apply(obj)
- 返回这个对象
注意这个时候,回顾下 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 的对象。
与寄生构造函数模式有两点不同:
- 新创建的实例方法不引用 this
- 不使用 new 操作符调用构造函数
稳妥对象最适合在一些安全的环境中。
稳妥构造函数模式也跟工厂模式一样,无法识别对象所属类型。
转载于:https://www.cnblogs.com/guaidianqiao/p/7762233.html
创建对象的多种方式以及优缺点相关推荐
- JavaScript继承的多种方式和优缺点
1.原型链继承 function Parent () {this.name = '张三'; }Parent.prototype.getName = function () {console.log(t ...
- Spring学习总结(一)——Spring实现IoC的多种方式
一.Spring框架概述 Spring是一个开源免费的框架,为了解决企业应用开发的复杂性而创建.Spring框架是一个轻量级的解决方案,可以一站式地构建企业级应用.Spring是模块化的,所以可以只使 ...
- 采用策略模式实现订单支付多种方式
背景 项目中订单支付为常见的功能,一般的订单支付都会包含多种方式,例如聚合支付.会员支付.积分支付的等多种方式,如果采用传统的方式来实现,需要使用多个if/else条件判断,本文将介绍如何采用策略+工 ...
- C#IO之导入导出Excel的多种方式
C#IO之导入导出Excel的多种方式 一.基本介绍: 今天给大家带来的是Excel导入导出的多种实现方式,以及他们的各自的优势以及劣势,首先第一种方式是使用Office组件的方式 ,第二种方式是使用 ...
- JS遍历数组的多种方式
JS遍历数组的多种方式 1. 普通for循环 for (let i = 0; i < arr.length; i++){//code} 应用最为普遍的循环写法,性能好,可读性好. 2. 优化版f ...
- JavaScript中的几种继承方式及优缺点,你知道多少呢?
原文连接:JavaScript中的几种继承方式及优缺点,你知道多少呢? 继承也是前端里面的重要的一个知识点,在实际工作中或者面试中也会经常的遇到,那么通过这篇文章我们详细的了解一下继承的几种方式以及各 ...
- python做定时任务的方式及优缺点_python BlockingScheduler定时任务及其他方式的实现...
本文介绍了python BlockingScheduler定时任务及其他方式的实现,具体如下: #BlockingScheduler定时任务 from apscheduler.schedulers.b ...
- java设计模式中不属于创建型模式_23种设计模式第二篇:java工厂模式定义:工厂模式是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式...
23种设计模式第二篇:java工厂模式 定义: 工厂模式是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 工厂模式主要是为创建对象提供过渡接口, ...
- C++多线程:thread类创建线程的多种方式
文章目录 描述 函数成员简介 总结 描述 头文件 <thread> 声明方式:std::thread <obj> 简介 线程在构造关联的线程对象时立即开始执行,从提供给作为构造 ...
最新文章
- 关于运维体系谈谈我的想法
- scheduledexecutorservice 的使用_使用J.U.C实现定时任务
- 启动celery后执行任务报错:django.core.exceptions.ImproperlyConfigured
- echarts3 graph java_Echarts中graph类型的运用求教
- android中将自己的自定义组件打成JAR包
- oauth2.0 学习案例demo_Vue3教程:用 Vue3 开发小程序,这里有一份实际的代码案例!...
- Zabbix监控nginx status
- 利用navicat for mysql实现mysql数据库表结构复制
- 20200728:力扣199周周赛题解(上)
- FIN7 正在转向密码重置和软件供应链攻击
- FlashDevelop 3.0.0 Beta2 released
- html实现横向轮播,js实现横向轮播效果
- stretchblt 模糊_微软开源持续开发模糊测试工具OneFuzz
- 2020Java学习路线(珍藏版)
- Java底层--JVM与GC
- 最强大脑记忆曲线(7)——“复习页面”逻辑实现
- 异步传输模式 (ATM)
- SAD SATD的区别及应用
- python格式和JSON格式转换
- elasticsearch的使用
热门文章
- filter过滤器_不了解布隆过滤器?一文给你整的明明白白
- mysql 动态创建事件_mysql 通过事件定时为数据库创建动态表名
- java 有序map_Java有序的Hash集合:LinkedHashMap
- python3.7 安装pip3_安装python3.7 pip3.7 去哪里了?
- 互联网+大赛作品_【快讯】智物联获第二届中国工业互联网大赛优秀作品奖
- java helper 设计模式_必知必会的 Java 设计模式入门知识(十):外观模式
- java 支付类的接口,Java后端支付大杂烩之core.dao,service,web(重点是接口的设计)(二)...
- vue element container 子路由
- Spring mvc @PathVaribale
- BS4 find_all