JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)


Posted in Javascript onAugust 16, 2014

什么是面向对象?面向对象是一种思想!(废话)。

面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法。这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作。接下来将为大家讲解在JS中面向对象的实现。

 

工厂模式

工厂模式是软件工程领域一种广为人知的设计模式,而由于在ECMAScript中无法创建类,因此用函数封装以特定接口创建对象。其实现方法非常简单,也就是在函数内创建一个对象,给对象赋予属性及方法再将对象返回即可。

function createBlog(name, url) {
  var o = new Object();
  o.name = name;
  o.url = url;
  o.sayUrl= function() {
    alert(this.url);
  }
  return o;
}

var blog1 = createBlog('wuyuchang', 'https://3water.com/');

可以看到工厂模式的实现方法非常简单,解决了创建多个相似对象的问题,但是工厂模式却无从识别对象的类型,因为全部都是Object,不像Date、Array等,因此出现了构造函数模式。

构造函数模式

ECMAScript中构造函数可以创建特定类型的对象,类似于Array、Date等原生JS的对象。其实现方法如下:

function Blog(name, url) {
  this.name = name;
  this.url = url;
  this.alertUrl = function() {
    alert(this.url);
  }
}

var blog = new Blog('wuyuchang', 'https://3water.com/');
console.log(blog instanceof Blog);  // true, 判断blog是否是Blog的实例,即解决了工厂模式中不能

这个例子与工厂模式中除了函数名不同以外,细心的童鞋应该发现许多不同之处:

函数名首写字母为大写

(虽然标准没有严格规定首写字母为大写,但按照惯例,构造函数的首写字母用大写
没有显示的创建对象
直接将属性和方法赋值给了this对象
没有return语句
使用new创建对象
能够识别对象(这正是构造函数模式胜于工厂模式的地方)

构造函数虽然好用,但也并非没有缺点,使用构造函数的最大的问题在于每次创建实例的时候都要重新创建一次方法(理论上每次创建对象的时候对象的属性均不同,而对象的方法是相同的),然而创建两次完全相同的方法是没有必要的,因此,我们可以将函数移到对象外面(也许有些童鞋已经看出缺点,嘘!)。

function Blog(name, url) {
  this.name = name;
  this.url = url;
  this.alertUrl = alertUrl;
}

function alertUrl() {
  alert(this.url);
}

var blog = new Blog('sc3water', 'http://sc.3water.com/'),
  blog2 = new Blog('3water', 'https://3water.com/');
blog.alertUrl();  // http://sc.3water.com/
blog2.alertUrl();  // https://3water.com/

我们将alertUrl设置成全局函数,这样一来blog与blog2访问的都是同一个函数,可是问题又来了,在全局作用域中定义了一个实际只想让Blog使用的函数,显示让全局作用域有些名副其实,更让人无法接受的是在全局作用域中定义了许多仅供特定对象使用的方法,浪费空间不说,显然失去了面向对象封装性了,因此可以通过原型来解决此问题。

  原型模式

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

function Blog() {
}

Blog.prototype.name = 'wuyuchang';
Blog.prototype.url = 'http://tools.3water.com/';
Blog.prototype.friend = ['fr1', 'fr2', 'fr3', 'fr4'];
Blog.prototype.alertInfo = function() {
  alert(this.name + this.url + this.friend );
}

// 以下为测试代码
var blog = new Blog(),
  blog2 = new Blog();
blog.alertInfo();  // wuyuchanghttp://tools.3water.com/fr1,fr2,fr3,fr4
blog2.alertInfo();  // wuyuchanghttp://tools.3water.com/fr1,fr2,fr3,fr4

blog.name = 'wyc1';
blog.url = 'http://***.com';
blog.friend.pop();
blog2.name = 'wyc2';
blog2.url = 'http://+++.com';
blog.alertInfo();  // wyc1http://***.comfr1,fr2,fr3
blog2.alertInfo();  // wyc2http://+++.comfr1,fr2,fr3

原型模式也不是没有缺点,首先,它省略了构造函数传递初始化参数这一环节,结果所有实例在默认情况下都取得了相同的属性值,这样非常不方便,但这还是不是原型的最大问题,原型模式的最大问题在于共享的本性所导致的,由于共享,因此因此一个实例修改了引用,另一个也随之更改了引用。因此我们通常不单独使用原型,而是结合原型模式与构造函数模式。

混合模式(原型模式 + 构造函数模式)

function Blog(name, url, friend) {
  this.name = name;
  this.url = url;
  this.friend = friend;
}

Blog.prototype.alertInfo = function() {
  alert(this.name + this.url + this.friend);
}

var blog = new Blog('wuyuchang', 'http://tools.3water.com/', ['fr1', 'fr2', 'fr3']),
  blog2 = new Blog('wyc', 'http://**.com', ['a', 'b']);

blog.friend.pop();
blog.alertInfo();  // wuyuchanghttp://tools.3water.com/fr1,fr2
blog2.alertInfo();  // wychttp://**.coma,b

混合模式中构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。每个实例都会有自己的一份实例属性,但同时又共享着方法,最大限度的节省了内存。另外这种模式还支持传递初始参数。优点甚多。这种模式在ECMAScript中是使用最广泛、认同度最高的一种创建自定义对象的方法。

动态原型模式

动态原型模式将所有信息封装在了构造函数中,而通过构造函数中初始化原型(仅第一个对象实例化时初始化原型),这个可以通过判断该方法是否有效而选择是否需要初始化原型。

function Blog(name, url) {
  this.name = name;
  this.url = url;

  if (typeof this.alertInfo != 'function') {
    // 这段代码只执行了一次
    alert('exe time');
    Blog.prototype.alertInfo = function() {
      alert(thia.name + this.url);
    }
  }
}

var blog = new Blog('wuyuchang', 'http://tools.3water.com'),
  blog2 = new Blog('wyc', 'http:***.com');

可以看到上面的例子中只弹出一次窗,'exe time',即当blog初始化时,这样做blog2就不在需要初始化原型,对于使用这种模式创建对象,可以算是perfect了。

此博文参考《JavaScript高级程序设计》第3版,但语言都经过简化,例子也重写过,如果有什么不懂的地方请留言回复,作者将更新博客。

Javascript 相关文章推荐
[转]JS宝典学习笔记
Feb 07 Javascript
jQuery)扩展jQuery系列之一 模拟alert,confirm(一)
Dec 04 Javascript
基于jquery实现漂亮的动态信息提示效果
Aug 02 Javascript
使用jquery.upload.js实现异步上传示例代码
Jul 29 Javascript
整理Javascript流程控制语句学习笔记
Nov 29 Javascript
理解javascript中的严格模式
Feb 01 Javascript
jQuery+ajax实现滚动到页面底部自动加载图文列表效果(类似图片懒加载)
Jun 07 Javascript
微信小程序-详解数据缓存
Nov 24 Javascript
微信小程序获取手机系统信息的方法【附源码下载】
Dec 07 Javascript
微信小程序实现循环动画效果
Jul 16 Javascript
详解Vue.js iview实现树形权限表(可扩展表)
Sep 30 Javascript
vue选项卡切换的实现案例
Apr 11 Vue.js
Node.js安装教程和NPM包管理器使用详解
Aug 16 #Javascript
Node.js中的事件驱动编程详解
Aug 16 #Javascript
Node.js文件操作详解
Aug 16 #Javascript
Node.js中使用Buffer编码、解码二进制数据详解
Aug 16 #Javascript
Node.js中创建和管理外部进程详解
Aug 16 #Javascript
Node.js模块加载详解
Aug 16 #Javascript
JS遍历Json字符串中键值对先转成JSON对象再遍历
Aug 15 #Javascript
You might like
PHP二维数组的去重问题解析
2011/07/17 PHP
PHP同时连接多个mysql数据库示例代码
2014/03/17 PHP
php中创建和调用webservice接口示例
2014/07/25 PHP
php计算多维数组中所有值总和的方法
2015/06/24 PHP
joomla组件开发入门教程
2016/05/04 PHP
thinkphp验证码的实现(form、ajax实现验证)
2016/07/28 PHP
php判断是否连接上网络的方法实例详解
2016/12/14 PHP
Yii框架实现的验证码、登录及退出功能示例
2017/05/20 PHP
javascript实现的使用方向键控制光标在table单元格中切换
2010/11/17 Javascript
基于jQuery的输入框无值自动显示指定数据的实现代码
2011/01/24 Javascript
JS的encodeURI和java的URLDecoder.decode使用介绍
2014/05/08 Javascript
jQuery事件之键盘事件(ctrl+Enter回车键提交表单等)
2014/05/11 Javascript
js实现漂浮回顶部按钮实例
2015/05/06 Javascript
JQuery+Ajax实现数据查询、排序和分页功能
2015/09/27 Javascript
微信小程序开发入门基础教程
2017/04/19 Javascript
详解在AngularJS的controller外部直接获取$scope
2017/06/02 Javascript
JS中使用cavas截图网页并解决跨域及模糊问题
2018/11/13 Javascript
微信小程序 checkbox使用实例解析
2019/09/09 Javascript
javascript异常处理实现原理详解
2020/02/17 Javascript
ES6扩展运算符和rest运算符用法实例分析
2020/05/23 Javascript
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
[01:42:49]DOTA2-DPC中国联赛 正赛 iG vs PSG.LGD BO3 第一场 2月26日
2021/03/11 DOTA
基于Python_脚本CGI、特点、应用、开发环境(详解)
2017/05/23 Python
Python实现的直接插入排序算法示例
2018/04/29 Python
Python实现数值积分方式
2019/11/20 Python
tensorflow 固定部分参数训练,只训练部分参数的实例
2020/01/20 Python
Python中使用socks5设置全局代理的方法示例
2020/04/15 Python
Python 创建TCP服务器的方法
2020/07/28 Python
Python Opencv轮廓常用操作代码实例解析
2020/09/01 Python
css3 矩阵的使用详解
2018/03/20 HTML / CSS
美国新兴城市生活方式零售商:VILLA
2017/12/06 全球购物
会议开场欢迎词
2014/01/15 职场文书
项目委托协议书(最新)
2014/09/13 职场文书
2014年保洁工作总结
2014/11/24 职场文书
公务员政审个人总结
2015/02/12 职场文书
Python绘制散乱的点构成的图的方法
2022/04/21 Python