全国服务热线:4008-888-888

公司新闻

好用的小程序引荐_[js高手之路]设计模式系列课程

[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例       下面小编就为大家带来一篇[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

一、买卖房子

生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色

中介拿到卖主的房源信息,根据手头上掌握的客户联系信息(买房的人的手机号),通知买房的人,他充当了发布者的角色

卖主想卖掉自己的房子,就需要告诉中介,把信息交给中介发布

二,网站订阅信息的用户

订阅者角色:需要订阅某类信息的网民,如某个网站的javascript类型文章

发布者角色:邮箱服务器,根据网站收集到的用户订阅邮箱,通知用户.

网站主想把信息告诉订阅者,需要把文章相关内容告诉邮箱服务器去发送

等等非常多的例子,不一一列举

本文用网站订阅的方式,推导发布者-订阅者框架,然后用发布者-订阅者框架来重构一个简单的购物车

var Site = {};
 Site.userList = [];
 Site.subscribe = function( fn ){
 this.userList.push( fn );
 Site.publish = function(){
 for( var i = 0, len = this.userList.length; i len; i++ ){
 this.userList[i].apply( this, arguments );
 Site.subscribe( function( type ){
 console.log( "网站发布了" + type + "内容" );
 Site.subscribe( function( type ){
 console.log( "网站发布了" + type + "内容" );
 Site.publish( 'javascript' );
 Site.publish( 'html5' );

Site.userList就是用来保存订阅者

Site.subscribe就是具体的订阅者,把每一个订阅者订阅的具体信息保存在Site.userList

Site.publish就是发布者:根据保存的userList,一个个遍历(通知),执行里面的业务逻辑

但是这个,发布订阅者模式,有个问题,不能订阅想要的类型,上例我加了2个订阅者(第11行,第14行),只要网站发了信息,全部能收到,但是有些用户可能只想收到javascript或者html5的,所以,接下来,我们需要继续完善,希望能够接收到具体的信息,不是某人订阅的类型,就不接收

var Site = {};
 Site.userList = {};
 Site.subscribe = function (key, fn) {
 if (!this.userList[key]) {
 this.userList[key] = [];
 this.userList[key].push(fn);
 Site.publish = function () {
 var key = Array.prototype.shift.apply(arguments),
 fns = this.userList[key];
 if ( !fns || fns.length === 0) {
 console.log( '没有人订阅' + key + "这个分类的文章" );
 return false;
 for (var i = 0, len = fns.length; i len; i++) {
 fns[i].apply(this, arguments);
 Site.subscribe( "javascript", function( title ){
 console.log( title );
 Site.subscribe( "es6", function( title ){
 console.log( title );
 Site.publish( "javascript", "[js高手之路]寄生组合式继承的优势" );
 Site.publish( "es6", "[js高手之路]es6系列教程 - var, let, const详解" );
 Site.publish( "html5", "html5新的语义化标签" );

输出结果:

[js高手之路]寄生组合式继承的优势

[js高手之路]es6系列教程 - var, let, const详解

没有人订阅html5这个分类的文章

我们可以看到,只有订阅了javascript类型文章的人,才能收到 ”寄生组合式继承的优势” 这篇文章,发布html5类型的时候,没有任何人会收到.

es6类型的,只有订阅es6的人,才能收到

我们已经有了一个基本的发布订阅者框架,接下来,把他完善成一个框架,便于其他功能或者其他网站系统的相同功能可以重用他

var Event = {
 userList : {},
 subscribe : function (key, fn) {
 if (!this.userList[key]) {
 this.userList[key] = [];
 this.userList[key].push(fn);
 publish : function () {
 var key = Array.prototype.shift.apply(arguments),
 fns = this.userList[key];
 if (!fns || fns.length === 0) {
 console.log('没有人订阅' + key + "这个分类的文章");
 return false;
 for (var i = 0, len = fns.length; i len; i++) {
 fns[i].apply(this, arguments);
 var extend = function( dstObj, srcObj ){
 for( var key in srcObj ){
 dstObj[key] = srcObj[key];
 var Site = {};
 extend( Site, Event );
 Site.subscribe( "javascript", function( title ){
 console.log( title );
 Site.subscribe( "es6", function( title ){
 console.log( title );
 Site.publish( "javascript", "寄生组合式继承的优势" );
 Site.publish( "es6", "es6系列教程 - var, let, const详解" );
 Site.publish( "html5", "html5新的语义化标签" );

然后,我们来重构一个购物车实例,没有重构之前,我的购物车用的是面向过程:

 !DOCTYPE html 
 html lang="en" 
 head 
 meta charset="UTF-8" 
 title Title /title 
 script src="js/cart.js" /script 
 /head 
 body 
 div id="box" 
 input type="button" value="-" 
 span 0 /span 
 input type="button" value="+" 
 span 单价: /span 
 span /span 
 span 小计: /span 
 span 0 /span 元
 /li 
 input type="button" value="-" 
 span 0 /span 
 input type="button" value="+" 
 span 单价: /span 
 span /span 
 span 小计: /span 
 span 0 /span 元
 /li 
 input type="button" value="-" 
 span 0 /span 
 input type="button" value="+" 
 span 单价: /span 
 span /span 
 span 小计: /span 
 span 0 /span 元
 /li 
 input type="button" value="-" 
 span 0 /span 
 input type="button" value="+" 
 span 单价: /span 
 span /span 
 span 小计: /span 
 span 0 /span 元
 /li 
 input type="button" value="-" 
 span 0 /span 
 input type="button" value="+" 
 span 单价: /span 
 span /span 
 span 小计: /span 
 span 0 /span 元
 /li 
 /ul 
 div 
 商品一共
 span id="goods-num" 0 /span 
 一共花费
 span id="total-price" 0 /span 
 其中最贵的商品单价是 span id="unit-price" 0 /span 元
 /div 
 /div 
 /body 
 /html 

cart.js文件:

function getByClass(cName, obj) {
 var o = null;
 if (arguments.length == 2) {
 o = obj;
 } else {
 o = document;
 var allNode = o.getElementsByTagName("*");
 var aNode = [];
 for( var i = 0 ; i allNode.length; i++ ){
 if( allNode[i].className == cName ){
 aNode.push( allNode[i] );
 return aNode;
function getSubTotal( unitPrice, goodsNum ){
 return unitPrice * goodsNum;
function getSum(){ //计算总花费
 var aSubtotal = getByClass("subtotal");
 var res = 0;
 for( var i = 0; i aSubtotal.length; i++ ){
 res += parseInt(aSubtotal[i].innerHTML);
 return res;
pareUnit() { //比单价,找出最高的单价
 var aNum = getByClass( "num");
 var aUnit = getByClass( "unit");
 var temp = 0;
 for( var i = 0; i aNum.length; i++ ){
 if( parseInt(aNum[i].innerHTML) != 0 ){
 if( temp parseInt(aUnit[i].innerHTML) ) {
 temp = parseInt(aUnit[i].innerHTML);
 return temp;
window.onload = function () {
 var aInput = document.getElementsByTagName("input");
 var total = 0;
 var oGoodsNum = document.getElementById("goods-num");
 var oTotalPrice = document.getElementById("total-price");
 var oUnitPrice = document.getElementById("unit-price");
 for (var i = 0; i aInput.length; i++) {
 if (i % 2 != 0) { //加号
 aInput[i].onclick = function () {
 //当前加号所在行的数量
 var aNum = getByClass( "num", this.parentNode );
 var n = parseInt( aNum[0].innerHTML );
 n++;
 aNum[0].innerHTML = n;
 //获取单价
 var aUnit = getByClass( "unit", this.parentNode );
 var unitPrice = parseInt(aUnit[0].innerHTML);
 var subtotal = getSubTotal( unitPrice, n );
 var aSubtotal = getByClass( "subtotal", this.parentNode );
 aSubtotal[0].innerHTML = subtotal;
 total++; //商品总数
 oGoodsNum.innerHTML = total;
 oTotalPrice.innerHTML = getSum();
 oUnitPrice.innerHTML = compareUnit();
 }else {
 aInput[i].onclick = function(){
 var aNum = getByClass( "num", this.parentNode );
 if ( parseInt( aNum[0].innerHTML ) != 0 ){
 var n = parseInt( aNum[0].innerHTML );
 n--;
 aNum[0].innerHTML = n;
 //获取单价
 var aUnit = getByClass( "unit", this.parentNode );
 var unitPrice = parseInt(aUnit[0].innerHTML);
 var subtotal = getSubTotal( unitPrice, n );
 var aSubtotal = getByClass( "subtotal", this.parentNode );
 aSubtotal[0].innerHTML = subtotal;
 total--; //商品总数
 oGoodsNum.innerHTML = total;
 oTotalPrice.innerHTML = getSum();
 oUnitPrice.innerHTML = compareUnit();
}

耦合度太高,可维护性很差.

重构之后的购物车:

window.onload = function () {
 var Event = {
 userList: {},
 subscribe: function (key, fn) {
 if (!this.userList[key]) {
 this.userList[key] = [];
 this.userList[key].push(fn);
 publish: function () {
 var key = Array.prototype.shift.apply(arguments),
 fns = this.userList[key];
 if (!fns || fns.length === 0) {
 return false;
 for (var i = 0, len = fns.length; i len; i++) {
 fns[i].apply(this, arguments);
 (function(){
 var aBtnMinus = document.querySelectorAll( "#box li input:first-child"),
 aBtnPlus = document.querySelectorAll( "#box li input:nth-of-type(2)"),
 curNum = 0, curUnitPrice = 0;
 for( var i = 0, len = aBtnMinus.length; i len; i++ ){
 aBtnMinus[i].index = aBtnPlus[i].index = i;
 aBtnMinus[i].onclick = function(){
 (this.parentNode.children[1].innerHTML 0) Event.publish( "total-goods-num-minus" );
 --this.parentNode.children[1].innerHTML 0 (this.parentNode.children[1].innerHTML = 0);
 curUnitPrice = this.parentNode.children[4].innerHTML;
 Event.publish( "minus-num" + this.index, 
 parseInt( curUnitPrice ),
 parseInt( this.parentNode.children[1].innerHTML )
 aBtnPlus[i].onclick = function(){
 (this.parentNode.children[1].innerHTML = 0) Event.publish( "total-goods-num-plus" );
 this.parentNode.children[1].innerHTML++;
 curUnitPrice = this.parentNode.children[4].innerHTML;
 Event.publish( "plus-num" + this.index, 
 parseInt( curUnitPrice ),
 parseInt( this.parentNode.children[1].innerHTML )
 })();
 (function(){
 var aSubtotal = document.querySelectorAll("#box .subtotal"),
 oGoodsNum = document.querySelector("#goods-num"),
 oTotalPrice = document.querySelector("#total-price");
 Event.subscribe( 'total-goods-num-plus', function(){
 ++oGoodsNum.innerHTML;
 Event.subscribe( 'total-goods-num-minus', function(){
 --oGoodsNum.innerHTML;
 for( let i = 0, len = aSubtotal.length; i len; i++ ){
 Event.subscribe( 'minus-num' + i, function( unitPrice, num ){
 aSubtotal[i].innerHTML = unitPrice * num;
 Event.subscribe( 'plus-num' + i, function( unitPrice, num ){
 aSubtotal[i].innerHTML = unitPrice * num;
 })();
 console.log( Event.userList );
}

以上这篇[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持凡科。




在线客服

关闭

客户服务热线
4008-888-888


点击这里给我发消息 在线客服

点击这里给我发消息 在线客服