JS常见构造模式实例对比分析


Posted in Javascript onAugust 27, 2018

本文实例分析了JS常见构造模式。分享给大家供大家参考,具体如下:

1.工厂模式

没有解决对象识别的问题。因为函数内部使用了new Object来创建对象

function Factory(name,age)
{
  var o=new Object();
  o.name=name;
  o.age=age;
  o.what=what;//用函数引用的方式消除重复创建相同函数的弊端,节省资源.函数引用可以修改this的指向,函数调用不可以!
  return o;
}
what=funciton()
{
  alert(this.name+this.age);
}
var o=Factory("12",12);
o.what();//what中的this指向o对象

这时候的constructor是Object,同时所有通过工厂模式返回的对象都是Object类型,所以instanceof操作符没有意义

console.log(o.constructor);
//打印function Object() { [native code] }
console.log(o instanceof Object);
//而且这时候所有的对象都是Object类型的

2.构造函数模式

function Person(name,age)
{
this.name=name;
this.age=age;
this.sayName=function(){ alert(this.name);}//相当于this.sayName=new Function("alert(this.name)")
}
var p1=new Person("xx",12);
var p2=new Person("yy",13);
alert(p1.sayName==p2.sayName)//内存地址不一样!返回false

构造函数相比工厂模式的优点在于能够正确的返回对象的类型,instanceof返回正确的结果。缺点在于如果向上面那样,那么在每一个对象上面都要有一个sayName方法,而且这些sayName方法不是同一个Function实例,因为ECMAScript中函数是对象,因此每定义一个函数,也就是实例化了一个对象!

对上面的方法进行优化:

function Person(name,age)
{
this.name=name;
this.age=age;
this.sayName=sayName;//函数引用的方法,共享了同一个sayName,p1,p2的内存地址一样,p1.sayName==p2.sayName返回true
}
function sayName()
{
alert(this.name);
}

缺点:全局函数sayName只能被某个对象调用p1.sayName,让全局函数名不副实;如果对象要定义很多方法,那么就要定义很多的全局函数,所以自定义的引用类型没有封装性可言

3.原型模式

(1)无法通过构造函数参数向原型属性动态传值,后果就是:没有个性,改变原型属性的值,所有的实例都会受到干扰!

(2)当原型属性的是引用类型的时候,如果在一个对象实例上修改属性,将会影响所有实例!

总之一句话:牵一发而动全身(包括属性和引用类型的值)是原型模式的特点。但是相比于构造函数类型,原型类型满足

person1.sayName===person2.sayName//两者的引用是一样的

4.构造函数原型模式

用构造函数定义个性,用原型模式定义共性

function Person(name,age)
{
 this.name=name;
 this.age=age;
 this.friends=['liangklfang','qinliang'];
}
//用原型定义共性
Person.prototype={
 constructor:Person,
 sayName:function()
 {
  console.log(this.name);
 }
}
var person1=new Person('liangklfang',"12");
var person2=new Person('liangklf',"14");
console.log(person1.sayName===person2.sayName);
//共性是函数,打印true
console.log(person1.friends===person2.friends);
//friends是个性,打印false

也可以对构造函数原型模式进行优化,就是常说的动态原型模式

function Book(title,page)
{
 this.title=title;
 this.page=page;
 if(typeof Book.isLock=="undefined")
//第一次的时候,Book.isLock是undefined,给原型绑定函数,以后就不需要了,他相比于构造函数原型模式的优点在于把所有的逻辑全部封装到构造函数里面!
  {
   alert("Enter!");
Book.prototype.what=function() 
     {
   alert(this.title+this.pages);
     }
   Book.isLock=true;
 }
}
//下面的两次调用alert("Enter!")只会调用因此i,因为第一次已经通过Book.isLock设置为true了!相当于静态方法!;
var b1=new Book("me",12);
b1.what();
var b2=new Book("he",13);
b2.what();

也可以在this中直接检测,而不用给函数对象一个属性

function Book(title,page)
{
 this.title=title;
 this.page=page;
  if(typeof this.sayName!='function')
  //第二次构造对象的时候会在原型中查找到sayName!
  {
   Book.prototype.sayName=function()
 {
  console.log(this.title);
 }
  }
}

5.寄生构造函数模式

除了使用new操作符以外,和工厂设计模式是一模一样的!可以在特殊的情况下为对象创建构造函数,例如想用构造函数方式创建一个具有额外方法的特殊数组,因为不能直接修改Array的构造函数,因此可以用这个模式!

function SpecialArray()
{
  var value=new Array();
  value.push.apply(value,arguments);
  value.toPipedString=function()
  {
    return this.join("|");
}
 return value;
}

总之,寄生构造函数的特点就是:有点像java中的装饰模式!把原来的对象进行装饰,同时返回装饰后的对象!这里就是把Array对象进行了装饰!添加了toPipe的String方法。缺点就是不能依赖instanceof操作符确定对象类型了,因为和不再包装类里面创建的对象是一模一样的!

6. 稳妥构造函数模式

特点:没有公共属性,而且其方法也不引用this的对象,instanceof失效。和寄生构造函数的不同在于不使用new来构造函数,同时实例方法不引用this。实际是闭包

function Person(name,age,job)
{
   var o=new Object();
    o.sayName=funciton(){alert(name)}//这里实例方法没有引用this,除了sayName不会有方法访问传入到构造函数中的原始数据!
   return o;
}
var friend=Person("xx",12,"teacher");
friend.name="female";//即使可以为这个对象修改了属性name
friend.sayName();//不会被修改,依然弹出xx。不是female。但是,如果把上面的修改成:o.sayName=function(){alert(this.name)}//那么就会弹出female,也就是friend.name被修改成功了,如果没有this,那么name的值一直引用的是原来的参数值!

感兴趣的朋友还可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试运行上述js代码。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
通用JS事件写法实现代码
Jan 07 Javascript
jQuery 树形结构的选择器
Feb 15 Javascript
jQuery 性能优化手册 推荐
Feb 23 Javascript
new Date()问题在ie8下面的处理方法
Jul 31 Javascript
JS+DIV实现鼠标划过切换层效果的方法
May 25 Javascript
javascript匀速运动实现方法分析
Jan 08 Javascript
jQuery获取当前点击的对象元素(实现代码)
May 19 Javascript
JS实现复制内容到剪贴板功能兼容所有浏览器(推荐)
Jun 17 Javascript
Vue-路由导航菜单栏的高亮设置方法
Mar 17 Javascript
Angular5.0 子组件通过service传递值给父组件的方法
Jul 13 Javascript
vue中使用mxgraph的方法实例代码详解
May 17 Javascript
详解Vuex下Store的模块化拆分实践
Jul 31 Javascript
Vue.js图片预览插件使用详解
Aug 27 #Javascript
JavaScript中创建原子的方法总结
Aug 26 #Javascript
解决vue.js 数据渲染成功仍报错的问题
Aug 25 #Javascript
解决Vue.js由于延时显示了{{message}}引用界面的问题
Aug 25 #Javascript
vue中各选项及钩子函数执行顺序详解
Aug 25 #Javascript
vue实现在一个方法执行完后执行另一个方法的示例
Aug 25 #Javascript
JS Object.preventExtensions(),Object.seal()与Object.freeze()用法实例分析
Aug 25 #Javascript
You might like
php 什么是PEAR?
2009/03/19 PHP
php数据结构与算法(PHP描述) 查找与二分法查找
2012/06/21 PHP
php环境套包 dedeampz 伪静态设置示例
2014/03/26 PHP
JavaScript创建命名空间的5种写法
2014/06/24 PHP
利用PHP获取网站访客的所在地位置
2017/01/18 PHP
php实现简单加入购物车功能
2017/03/07 PHP
让你的博文自动带上缩址的实现代码,方便发到微博客上
2010/12/28 Javascript
JS 有趣的eval优化输入验证实例代码
2013/09/22 Javascript
只需一行代码,轻松实现一个在线编辑器
2013/11/12 Javascript
javaScript对文字按照拼音排序实现代码
2013/12/27 Javascript
javascript计时器详解
2015/02/28 Javascript
JavaScript中string对象
2015/06/12 Javascript
js模仿java的Map集合详解
2016/01/06 Javascript
jQuery版本升级踩坑大全
2016/01/12 Javascript
JS设置手机验证码60s等待实现代码
2017/06/14 Javascript
vue 1.x 交互实现仿百度下拉列表示例
2017/10/21 Javascript
微信小程序自定义组件实现tabs选项卡功能
2018/07/14 Javascript
微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
2018/10/12 Javascript
JavaScript两种计时器的实例讲解
2019/01/31 Javascript
微信小程序点击滚动到指定位置的实现
2020/05/22 Javascript
[54:24]Optic vs TNC 2018国际邀请赛小组赛BO2 第二场
2018/08/18 DOTA
Python 备份程序代码实现
2017/03/06 Python
python字典的遍历3种方法详解
2019/08/10 Python
numpy矩阵数值太多不能全部显示的解决
2020/05/14 Python
python3列表删除大量重复元素remove()方法的问题详解
2021/01/04 Python
全球独特生活方式产品和礼品购物网站:AHAlife
2018/09/18 全球购物
网络安全方面的面试题
2015/11/04 面试题
注塑工厂厂长岗位职责
2013/12/02 职场文书
5.1手机促销活动
2014/01/17 职场文书
联谊活动策划书
2014/01/26 职场文书
生日主持词
2014/03/20 职场文书
计算机科学与技术专业求职信
2014/09/03 职场文书
秋季运动会演讲稿
2014/09/16 职场文书
学校群众路线专项整治方案
2014/10/31 职场文书
微软Win11什么功能最惊艳? Windows11新功能特性汇总
2021/11/21 数码科技
SSM项目使用拦截器实现登录验证功能
2022/01/22 Java/Android