JavaScript面向对象OOM 2(JavaScript 创建对象的工厂模式和构造函数模式)
在创建对象的时候,使用对象字面量和 new Object() 构造函数的方式创建一个对象是最简单最方便的方式。但是凡是处于初级阶段的事物都会不可避免的存在一个问题,没有普适性,意思就是说我要为世界上(程序中)的所有使用到的对象都使用一遍 var xxx = {}
,对于'懒惰'的程序员来讲是不可以接受的。即便你能接受这种创建的方式,也无法保证将所有对象归类这一哲学问题。
由此,优秀的程序员们利用现有的规则,创造出了一种种优秀的解决方案 -- 这些优秀的解决方案统称为设计模式。
在 JavaScript 中,设计模式由初级到高级的区别是他们的副作用的大小。依次可以分为:
- 工厂模式
- 构造函数模式
- 原型模式
- others
同时,使用设计模式也可以优雅的解决 JavaScript 在 ES6之前都是没有类的尴尬问题。
工厂模式
工厂模式,顾名思义就是创建对象的一个工厂,工厂可以创造一类具有相似结构和功能的对象。这个模式的诞生也<span style="color: red">基本</span>解决了:
- 创建多个对象的时候,需要大量重复代码
先看下在这种设计模式下,应该如何组织我们的代码:
function createPerson(name, age) {
var obj = new Object();
obj.name = name ;
obj.age = age;
obj.say = function() { console.log(this.name)}
return obj;
}
var p1 = createPerson('ZhangSan', 12);
p1.say() //ZhangSan
- 这种叫工厂模式的设计模式:是指使用统一的方法(函数,因为 Js 没有类)来描述对象创建的细节
- 把这个对象封装起来,每次使用类似的对象都使用这个工厂函数来创建。
- 它抽象了创建一个对象的过程。
当然,处于初级阶段的 工厂模式, 一定有它处于初级阶段的道理:
优势:
- 工厂函数可以解决创建多个类似功能对象的问题。
缺点:
- 工厂模式无法解决对象的识别问题: 不知道对象是什么类型的。
- 使用工厂函数创建的对象,只有开发者是知道它的类型的(通过工厂函数变量名),但是程序仍然认为它是一个普通的对象。
- 每个对象都是通过工厂造就的全新的对象。
构造函数模式
在 JavaScript 的开发中,经常会听说和使用的一个词语叫做构造函数,这里的构造函数就是出自构造函数模式这一种设计模式。在长时间的传承中,文化或者其他的名词都会变成一种泛称,所以人们常说的构造函数,有的时候指的是构造函数模式,有的时候指的是构造函数模式创造的对象中的构造函数方法(实例的 constructor )。
构造函数是用来创建特定的类型的对象的。比如Js原生提供的Object
, Array
。都是构造函数模式创建的原生构造函数。
惯例,看下在这种设计模式下,该如何组织代码:
function Person (name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(this.age);
}
}
var p1 = new Person('ZhangSan', 12);
var p2 = new Person('LiSi', 22);
p1.say() // 12
p2.say() // 22
使用构建函数模式和工厂模式创建对象的区别:
- 没有明显的创建对象的过程: (
new Object()
的过程) - 直接将参数赋值给了 this。(因为 没有创建明显的对象,就需要用 this 进行赋值)
- 没有 return 。
- 构造函数的首字母大写,这是代码风格上的变化(为了和其他的 OOM 语言的代码风格保持一致)
- 没有明显的创建对象的过程: (
- 创建一个由构造函数创建的对象,需要使用
new Person()
进行创建。 使用构造函数创建对象经历了以下四个过程:
- 创建一个新对象
- 构造函数的作用域交给新对象。this指向新对象
- 执行内部代码,给新对象增加属性和方法
- 返回新对象
由构造函数创建的对象称为这个构造函数的<span style="color: red">实例</span>,在实例中会存在一个 constructor 属性,这个属性指向创造它的构造函数。(证明自己从哪里来)
p1.constructor == Person; // true
p2.constructor == Person; // true每一个实例都是可以被检测出来的,检测对象是否属于某一个类型,可以使用
instanceof XX
。p1 instanceof Person // true
p1 instanceof Object // true
知道了构造函数模式创建实例的过程和方法,下面介绍一些使用构造函数方法中,一些不为人知的秘密(高级知识点):
- 使用构造函数的时候常规操作是:使用操作符
new
。但是也可以直接当做一个普通的函数使用。
// Person 在上个 Demo
var p3 = Person('Person3', 33);
p3; // undefined;
p3.say(); // undefined;
Person('Person4', 44);
window.say(); // 44;
- 如果把构造函数当做普通函数使用了,就不能构造实例了,即使构造了实例,也都是
undefined
。 - 直接使用 构造函数当做普通函数使用, 属性和方法会被添加到全局中(window/global)。
- 当然也可以使用
call
把 this 指向其他对象。(不了解 call,可以先忽略。call 是改变 this 指针的方式之一)。
了解了高级用法之后,细心的孩子已经发现了构造函数方法作为 Level 2的设计模式,一定有哪里不对。其实很简单,在构造函数创建的过程中,很好的解决了工厂模式创建对象不知道类型的问题(不知道自己从哪里来)。在构想上,实例的属性和方法应该都是唯一指向的,理想情况是都指向构造函数。但是差强人意的地方出现了:
- 属性都很好的指向了 构造函数。
this.name = name
- 方法又自己偷摸的创建了新的对象(函数也是对象)。这就不符合理想的情况了,因为这个时候:
p1.say === p2.say // false
- 原理也很清楚啊:
this.say = function() {}
就是this.say = new Function()
啊。
这个时候,一个构造函数的补救措施出现了:
var Person = function(name, age) {
this.name = name;
this.age = age;
this.say = sayFunc;
}
var sayFunc = function() {
console.log(this.age)
}
- 使用额外的函数,将构造函数内的方法指向外部,这样就保证了实例方式的相同。
<u>俗话说的好,补救措施终究是补救措施</u>:
- 在构造函数存在大量的方法的时候,外部会存在数量巨多的补救方法。
- 补救方法在构造函数的外部,毫无封装性可言。
- 外部方法也是一个普通的函数,也可以被其他方法或构造函数执行。
- 外部方法被添加到 全局(window/global)上,性能浪费。如果在 window 上调用,this 就指向了 window。造成 this 指向混乱(谁调用,this 指向谁)
所以,构造函数的方法仍然是一个不完美的方法。但是在开发速度上,构造函数的设计模式还是有很大优势的。
而且当你需要你的方法在全局被使用的时候,构造函数模式是最适合的,这也是 Object, Array
原生构造函数出现的原因。
JavaScript面向对象OOM 2(JavaScript 创建对象的工厂模式和构造函数模式)的更多相关文章
- javascript 面向对象编程(工厂模式、构造函数模式、原型模式)
javascript 面向对象编程(工厂模式.构造函数模式.原型模式) CreateTime--2018年3月29日17:09:38 Author:Marydon 一.工厂模式 /** * 工厂模 ...
- 重学js之JavaScript 面向对象的程序设计(创建对象)
注意: 本文章为 <重学js之JavaScript高级程序设计>系列第五章[JavaScript引用类型]. 关于<重学js之JavaScript高级程序设计>是重新回顾js基 ...
- javascript面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法.这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.接下来将为大家讲解在JS中面向对象的实现. 工厂 ...
- javascript面向对象系列第二篇——创建对象的5种模式
× 目录 [1]字面量 [2]工厂模式 [3]构造函数[4]原型模式[5]组合模式 前面的话 如何创建对象,或者说如何更优雅的创建对象,一直是一个津津乐道的话题.本文将从最简单的创建对象的方式入手,逐 ...
- js面向对象、创建对象的工厂模式、构造函数模式、原型链模式
JS面向对象编程(转载) 什么是面向对象编程(OOP)?用对象的思想去写代码,就是面向对象编程. 面向对象编程的特点 抽象:抓住核心问题 封装:只能通过对象来访问方法 继承:从已有对象上继承出新的对象 ...
- 面向对象JS基础讲解,工厂模式、构造函数模式、原型模式、混合模式、动态原型模式
什么是面向对象?面向对象是一种思想!(废话). 面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法.这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.接下 ...
- JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
什么是面向对象?面向对象是一种思想. 面向对象可以把程序中的关键模块都视为对象, 而模块拥有属性及方法. 这样如果我们把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作. 工厂 ...
- javascript面向对象程序设计系列(一)---创建对象
javascript是一种基于对象的语言,但它没有类的概念,所以又和实际面向对象的语言有区别,面向对象是javascript中的难点之一.现在就我所理解的总结一下,便于以后复习: 一.创建对象 1.创 ...
- javascript工厂模式和构造函数模式创建对象
一.工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(本书后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创 ...
随机推荐
- python基础知识(字符串)
定义字符串 ' '单引号 " "双引号 只能用于单行 '" '"三引号 可以用于多行 拼接字符串使用 +号链接 字符串只能链接字符串其他类型字符串需要用s ...
- Linux C\C++基础 字符数组、字符串和字符串常量
1.字符数组和字符串 C语言没有字符串类型,用字符数组模拟 字符串一定是字符数组,字符数组不一定是字符串 如果字符数组以字符'\0'('\0'等同与数字0)结尾,那么这个字符数组就是字符串 char ...
- 通俗易懂的lambda表达式,不懂来找我!
lambda是Python编程语言中使用频率较高的一个关键字.那么,什么是lambda?它有哪些用法?网上的文章汗牛充栋,可是把这个讲透的文章却不多.这里,我们通过阅读各方资料,总结了关于Python ...
- 一加手机刷入第三方Rec
首先阐述一下刷机的整体流程: 备份数据(可选):短信.联系人.通话记录.图片.应用数据的云端同步. 解锁 刷入第三方Recovery(简称Rec). 进入第三方Rec,刷第三方ROM. 刷机成功 解锁 ...
- NumPy进阶
数组算术 任何两个等尺寸数组之间的算术操作都应用了逐元素操作的方式. arr1 = np.array([[1,2,3],[4,5,6]]) arr2 = np.array([[4,2,1],[7,2, ...
- Eclipse中导入Maven Web项目并配置其在Tomcat中运行
今天因为实习的关系需要讲公司已经开发的项目导入进Eclipse,而公司的项目是用Maven来构建的所以,需要将Maven项目导入进Eclipse下. 自己因为没有什么经验所以搞了得两个多小时,在这里和 ...
- 掌握Mybatis的核心配置文件
一.配置文件结构 MyBatis的核心配置文件配置了MyBatis的一些全局信息,包含数据库连接信息和MyBatis运行时所需的各种特性,以及设置和影响MyBatis行为的一些属性. 该配置文件的元素 ...
- ubuntu18.04 开机自动启动脚本的坑
哇 这个真的难受 找了半天的方案不能用 自暴自弃用的图形界面设置
- 2-SAT问题介绍求解 + 模板题P4782
(点击此处查看原题) 什么是2-SAT问题 sat 即 Satisfiability,意思为可满足,那么2-SAT表示一些布尔变量只能取true或者false,而某两个变量之间的值存在一定的关系(如: ...
- CF 1133B Preparation for International Women's Day
题目链接:http://codeforces.com/problemset/problem/1133/B 题目分析 读完题目,凡是先暴力.....(不用想,第四组数据就TLE了,QAQ) 当两个数的和 ...