当前位置: 首页 > 编程日记 > 正文

js模块化例子

最近在看一本书,里面提到js的模块化,觉得很有必要,所以记录下来
Game.js

/*** This is the main class that handles the game life cycle. It initializes* other components like Board and BoardModel, listens to the DOM events and* translates clicks to coordinates.* @param canvas the canvas object to use for drawing*/
function Game(canvas) {this._boardRect = null;this._canvas = canvas;this._ctx = canvas.getContext("2d");this._boardModel = new BoardModel();//实例化类this._boardRenderer = new boardRenderer(this._ctx, this._boardModel);this.handleResize();
}_h = Game.prototype;/*** Handles the click (or tap) on the Canvas. Translates the canvas coordinates* into the column of the game board and makes the next turn in that column* @param x the x coordinate of the click or tap* @param y the y coordinate of the click or tap*/
_h.handleClick = function(x, y) {// 获取列的索引var column = Math.floor((x - this._boardRect.x)/this._boardRect.cellSize);//生成回合并检查结果var turn = this._boardModel.makeTurn(column);// 如果回合有效,更新游戏盘并绘制新球if (turn.status != BoardModel.ILLEGAL_TURN) {this._boardRenderer.drawToken(turn.x, turn.y);}// Do we have a winner after the last turn?if (turn.status == BoardModel.WIN) {// Tell the world about it and reset the board for the next gamealert((turn.piece == BoardModel.RED ? "red" : "green") + " won the match!");this._reset();}// If we have the draw, do the sameif (turn.status == BoardModel.DRAW) {alert("It is a draw!");this._reset();}
};/*** Reset the _boardModel and redraw the board.*/
_h._reset = function() {this._clearCanvas();this._boardModel.reset();this._boardRenderer.repaint();
};/*** Called when the screen has resized. In this case we need to calculate* new size and position for the game board and repaint it.*/
_h.handleResize = function() {this._clearCanvas();this._boardRect = this._getBoardRect();//拿到画棋盘的3个重要参数this._boardRenderer.setSize(this._boardRect.x, this._boardRect.y, this._boardRect.cellSize);this._boardRenderer.repaint();
};/*** Get the optimal position and the size of the board* @return the object that describes the optimal position and* size for the board:* {*      x: the x of the top-left corner of the board*      y: the y of the top-left corner of the board*      cellSize: the optimal size of the cell (in pixels)* }*/
_h._getBoardRect = function() {var cols = this._boardModel.getCols();//这个游戏的列数var rows = this._boardModel.getRows();//这个游戏的行数var cellSize = Math.floor(Math.min(this._canvas.width/cols, this._canvas.height/rows));//每个单元格的长var boardWidth = cellSize*cols;var boardHeight = cellSize*rows;return {x: Math.floor((this._canvas.width - boardWidth)/2),y: Math.floor((this._canvas.height - boardHeight)/2),cellSize: cellSize}
};/*** 清除画布的方法居然是直接在画布上面画一个白色的矩形!不需要使用clearRect()...* 但是如果背景是一张图片,直接就可以用这个方法*/
_h._clearCanvas = function() {this._ctx.fillStyle = "white";this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
};

boardRenderer.js

/*** 这个类负责绘制,棋盘,球* @param context the 2d context to draw at* @param model the BoardModel to take data from*/
function boardRenderer(context,model){this._ctx = context;this._model = model;//为方便保存this._cols = model.getCols();this._rows = model.getRows();//游戏盘左上角的位置this._x = 0;this._y = 0;//游戏盘矩形的宽度和高度this.width = 0;this.height = 0;//游戏盘单元格的最佳大小this._cellSize = 0;
}_h = boardRenderer.prototype;/*** 重新绘制整个画板Repaints the whole board.*/
_h.repaint = function() {this._ctx.save();this._ctx.translate(this._x, this._y);this._drawBackground();this._drawGrid();this._ctx.restore();for (var i = 0; i < this._cols; i++) {for (var j = 0; j < this._rows; j++) {this.drawToken(i, j);}}
};/*** 画背景**/
_h._drawBackground = function(){var ctx = this._ctx;//背景var gradient = ctx.createLinearGradient(0,0,0,this._height);gradient.addColorStop(0,"#fffbb3");gradient.addColorStop(1,"#f6f6b2");ctx.fillStyle = gradient;ctx.fillRect(0,0,this._width,this._height);//绘制曲线var co = this.width/6;ctx.strokeStyle = "#dad7ac";ctx.fillStyle = "#f6f6b2";//第一条曲线ctx.beginPath();ctx.moveTo(co, this._height);ctx.bezierCurveTo(this._width + co*3, -co, -co*3, -co, this._width - co, this._height);ctx.fill();//第二条曲线ctx.beginPath();ctx.moveTo(co, 0);ctx.bezierCurveTo(this._width + co*3, this._height + co, -co*3, this._height + co, this._width - co, 0);ctx.fill();
}/*** 画网格.*/
_h._drawGrid = function() {var ctx = this._ctx;ctx.beginPath();//画横线 Drawing horizontal linesfor (var i = 0; i <= this._cols; i++) {ctx.moveTo(i*this._cellSize + 0.5, 0.5);ctx.lineTo(i*this._cellSize + 0.5, this._height + 0.5)}//画竖线 Drawing vertical linesfor (var j = 0; j <= this._rows; j++) {ctx.moveTo(0.5, j*this._cellSize + 0.5);ctx.lineTo(this._width + 0.5, j*this._cellSize + 0.5);}//给这些线描边ctx.strokeStyle = "#CCC";ctx.stroke();
};/*** 在指定的地方画上指定颜色的标记* @param cellX 单元格的x坐标* @param cellY 单元格的y坐标*/
_h.drawToken = function(cellX, cellY) {var ctx = this._ctx;var cellSize = this._cellSize;var tokenType = this._model.getPiece(cellX, cellY);//如果单元格为空if (!tokenType)return;var colorCode = "black";switch(tokenType) {case BoardModel.RED:colorCode = "red";break;case BoardModel.GREEN:colorCode = "green";break;}//标记的圆心位置var x = this._x + (cellX + 0.5)*cellSize;var y = this._y + (cellY + 0.5)*cellSize;ctx.save();ctx.translate(x, y);//标记的半径var radius = cellSize*0.4;//渐变的中心var gradientX = cellSize*0.1;var gradientY = -cellSize*0.1;var gradient = ctx.createRadialGradient(gradientX, gradientY, cellSize*0.1, // 内圆 (炫光)gradientX, gradientY, radius*1.2); // 外圆gradient.addColorStop(0, "yellow"); // “光线”的颜色gradient.addColorStop(1, colorCode); // 标记的颜色ctx.fillStyle = gradient;ctx.beginPath();ctx.arc(0, 0, radius, 0, 2*Math.PI, true);ctx.fill();ctx.restore();
};/*** Sets the new position and size for the board. Should call repaint to* see the changes* @param x the x coordinate of the top-left corner* @param y the y coordinate of the top-left corner* @param cellSize optimal size of the cell in pixels*/
_h.setSize = function(x, y, cellSize)  {this._x = x;this._y = y;this._cellSize = cellSize;this._width = this._cellSize*this._cols;this._height = this._cellSize*this._rows;
};

boardModel.js

/*** 这个类是负责保存/验证/返回当前游戏的状态* 如当前的玩家是谁、每个单元格放的是什么球、* 是不是谁赢了* @param cols number of columns in the board* @param rows number of rows in the board*/
function BoardModel(cols, rows) {this._cols = cols || 7;this._rows = rows || 6;this._data = [];//用于记录游戏当前的游戏状态——每个格子有什么球this._currentPlayer = BoardModel.RED;this._totalTokens = 0;this.reset();
}/*** 0代表单元格为空,1代表单元格有红色球,2代表单元格有绿色球* 因为怕以后忘记这些数字代表什么,干脆把数字存到常量里,代码看起来易懂,* 但是这么多字,前端的js不是应该越短越好吗!?* ps.变量名全大写表示这是常量,这是一个js程序员之间的约定,表达为 CAPITAL_CASED。* 另外一个与变量(函数)有关的约定是:变量名(函数名)前加"_"下横杠,表示这是私有变量(函数),表达为 _underlinePrivateVariables*/
BoardModel.EMPTY = 0;
BoardModel.RED = 1;
BoardModel.GREEN = 2;/*** Game state after the turn*/
BoardModel.NONE = 0; // 没有赢也没有平局
BoardModel.WIN = 1; //刚刚着棋的玩家赢了
BoardModel.DRAW = 2; // 棋盘满了,且平局
BoardModel.ILLEGAL_TURN = 3; // 刚刚着棋的玩家,走棋无效,再走一次_h = BoardModel.prototype;/*** Resets the game board into the initial state: the* board is empty and the starting player is RED.*/
_h.reset = function() {this._data = [];for (var i = 0; i < this._rows; i++) {this._data[i] = [];for (var j = 0; j < this._cols; j++) {this._data[i][j] = BoardModel.EMPTY;}}this._currentPlayer = BoardModel.RED;this._totalTokens = 0;
};/*** 把球放到指定列。 Board model itself takes care of* tracking the current player.* @param column the index of the column* @param piece the ID of the piece (RED or YELLOW)* @return the object {*      status: win condition*      x: the x coordinate of the new turn (undefined if turn was illegal)*      y: the y coordinate of the new turn (undefined if turn was illegal)*      piece: piece id (RED or GREEN)* }*/
_h.makeTurn = function(column) {//正在放的球的颜色 The color of the piece that we're droppingvar piece = this._currentPlayer;//检查这一列是否可以放球if (column < 0 || column >= this._cols) {return {status: BoardModel.ILLEGAL_TURN}}//检查这一列上有空行没,如果没有,则这回合无效var row = this._getEmptyRow(column);if (row == -1) {return {status: BoardModel.ILLEGAL_TURN}}//放置球this._totalTokens++;this._data[row][column] = piece;// 更换玩家this._toggleCurrentPlayer();// 返回回合成功的消息,包括新的游戏状态:none——可以继续游戏、win、drawreturn {status: this._getGameState(column, row),x: column,y: row,piece: piece}
};_h.getPiece = function(col, row) {return this._data[row][col];
};/*** 返回这个游戏有多少列*/
_h.getCols = function() {return this._cols;
};/*** 返回这个游戏有多少行*/
_h.getRows = function() {return this._rows;
};/*** 返回指定列是否有空行,如果没有 return -1.* @param column the column index*/
_h._getEmptyRow = function(column) {for (var i = this._rows - 1; i >= 0; i--) {if (!this.getPiece(column, i)) {return i;}}return -1;
};/*** Checks for the win condition, checks how many pieces of the same color are in each* possible row: horizontal, vertical or both diagonals.* @param column the column of the last move* @param row the row of the last move* @return the game state after this turn:*  NONE if the state wasn't affected*  WIN if current player won the game with the last turn*  DRAW if there's no emty cells in the board left*/
_h._getGameState = function(column, row) {if (this._totalTokens == this._cols*this._rows)return BoardModel.DRAW;for (var deltaX = -1; deltaX < 2; deltaX++) {for (var deltaY = -1; deltaY < 2; deltaY++) {if (deltaX == 0 && deltaY == 0)continue;var count = this._checkWinDirection(column, row, deltaX, deltaY)+ this._checkWinDirection(column, row, -deltaX, -deltaY) + 1;if (count >= 4) {return BoardModel.WIN;}}}return BoardModel.NONE;
};/*** Calculates the number of pieces of the same color in the given direction, starting* fromt the given point (last turn)* @param column starting column* @param row starting row* @param deltaX the x direction of the check* @param deltaY the y direction of the check*/
_h._checkWinDirection = function(column, row, deltaX, deltaY) {var pieceColor = this.getPiece(column, row);var tokenCounter = 0;var c = column + deltaX;var r = row + deltaY;while(c >= 0 && r >= 0 && c < this._cols && r < this._rows &&this.getPiece(c, r) == pieceColor) {c += deltaX;r += deltaY;tokenCounter++;}return tokenCounter;
};/*** 切换当前玩家 - from red to green and back.*/
_h._toggleCurrentPlayer = function() {this._currentPlayer = (this._currentPlayer==BoardModel.RED)?BoardModel.GREEN:BoardModel.RED;/*if (this._currentPlayer == BoardModel.RED)this._currentPlayer = BoardModel.GREEN;elsethis._currentPlayer = BoardModel.RED;*/
};

相关文章:

swift3.0提示框新用法

var alert: UIAlertController! alert UIAlertController(title: "提示", message: "添加照片", preferredStyle: UIAlertControllerStyle.actionSheet) let cleanAction UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel,han…

FFmpeg在Windows上通过dshow编解码方式设置为mjpeg并实时显示测试代码

Windows上默认的内置摄像头一般支持两种编解码格式&#xff1a;rawvideo和mjpeg。在调用FFmpeg接口时默认的采用rawvideo。这里通过DirectShow实现为mjpeg进行编解码。 通过命令行调用FFmpeg可执行文件&#xff1a; (1). 可获取Windows上连接的视频设备&#xff0c;命令如下&…

基于深度学习的低光照图像增强方法总结(2017-2019)| CSDN博文精选

扫码参与CSDN“原力计划”作者 | hyk_1996来源 | CSDN博客精选之前在做光照对于高层视觉任务的影响的相关工作&#xff0c;看了不少基于深度学习的低光照增强&#xff08;low-light enhancement&#xff09;的文章[3,4,5,7,8,9,10]&#xff0c;于是决定简单梳理一下。光照估计&…

ios多线程和进程的区别(转载)

很想写点关于多进程和多线程的东西&#xff0c;我确实很爱他们。但是每每想动手写点关于他们的东西&#xff0c;却总是求全心理作祟&#xff0c;始终动不了手。 今天终于下了决心&#xff0c;写点东西&#xff0c;以后可以再修修补补也无妨。 一.为何需要多进程&#xff08;或者…

OC封装的轮播图-只用调用即可

先来使用方法 1.//创建显示本地图片view UIView *imageScorll[WTImageScroll ShowLocationImageScrollWithFream:CGRectMake(0, 0, SCREENWIDTH, 200) andImageArray:array andBtnClick:^(NSInteger tagValue) { NSLog("点击的图片----%",(tagValue)); self.didSele…

多核时代,并行编程为何“臭名昭著”?

作者 | Yan Gu来源 | 转载自知乎用户Yan Gu【导读】随着计算机技术的发展&#xff0c;毫无疑问现代计算机的处理速度和计算能力也越来越强。然而细心的同学们可能早已注意到&#xff0c;从2005年起&#xff0c;单核的 CPU 性能就没有显著的提升了。究其原因&#xff0c;是人们发…

Linux下获取usb视频设备vendor id和product id的8种方法

在使用usb摄像头获取视频时&#xff0c;有时需要获取此摄像头供应商ID(vendor id, vid)和产品ID(product id, pid)&#xff0c;这里在Linux下提供获取vid和pid的8种方法&#xff1a; 1. 通过v4l2中结构体v4l2_capability的成员变量card&#xff1a;此变量中会包含设备名、vid、…

JAVA 设计模式 模板方法模式

定义 模板方法模式 (Template Method) 定义了一个操作中的算法的骨架&#xff0c;而将部分步骤的实现在子类中完成。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法模式是所有模式中最为常见的几个模式之一&#xff0c;是基于继承的代…

这类程序员成华为宠儿,分分钟秒杀众应届毕业生

近日&#xff0c;华为20亿奖励员工的新闻频频刷屏。其中20亿奖金不是面向所有的华为员工&#xff0c;20亿奖金包涉及到的是研发体系、造AI芯片和建设生态的员工。从5G开始部署以来&#xff0c;华为获得了来自全球各地运营商的订单&#xff0c;签订了40多个5G商用合同。另外华为…

Swift 使用CoreLocation获取定位与位置信息

大多数情况下APP会在开启应用的时候获取当前的位置&#xff0c;所以我写在APPDelegate里第一步 import CoreLocationvar locationManager CLLocationManager() 第二步func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: …

FFmpeg在Windows上设置dshow mjpeg编码+libyuv解码显示测试代码

之前在https://blog.csdn.net/fengbingchun/article/details/103444891中介绍过在Windows上通过ffmpeg dshow设置为mjpeg编解码方式进行实时显示的测试代码。这里测试仅调用ffmpeg的mjpeg编码接口&#xff0c;获取到packet后&#xff0c;通过libyuvlibjpeg-turbo对mjpeg进行解码…

转:浅谈Linux的内存管理机制

一 物理内存和虚拟内存 我们知道&#xff0c;直接从物理内存读写数据要比从硬盘读写数据要快的多&#xff0c;因此&#xff0c;我们希望所有数据的读取和写入都在内存完成&#xff0c;而内存是有限的&#xff0c;这样就引出了物理内存与虚拟内存的概念。 物理内存就是系统硬件提…

swift3.0阿里百川反馈

闲言少叙 直接上不熟 1.导入自己工程阿里百川demo中的Util文件,并引用其中的头文件 2.剩余就是swift3.0代码.在自己需要的地方书写 (前提是你已经申请了APPKey) 3.代码 //调用意见反馈 func actionOpenFeedback(){ //key self.appKey "此处填写自己申请的key" s…

通俗易懂:8大步骤图解注意力机制

作者 | Raimi Karim译者 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;【导读】这是一份用图片和代码详解自注意力机制的指南&#xff0c;请收好。BERT、RoBERTa、ALBERT、SpanBERT、DistilBERT、SesameBERT、SemBERT、MobileBERT、TinyBERT和CamemBERT的共同…

Windows上VS2017单步调试FFmpeg源码的方法

之前在https://blog.csdn.net/fengbingchun/article/details/90114411 介绍过如何在Windows7/10上通过MinGW方式编译FFmpeg 4.1.3源码生成库的步骤&#xff0c;那时只能生成最终的库&#xff0c;却不能产生vs工程&#xff0c;无法进行单步调试。GitHub上有个项目ShiftMediaProj…

ormlite 多表联合查询

ormlite 多表联合查询 QueryBuilder shopBrandQueryBuilder shopBrandDao.queryBuilder(); QueryBuilder shopQueryBuilder shopDao.queryBuilder();Where shopBrandWhere shopBrandQueryBuilder.where(); shopBrandWhere .eq(ShopBrand.SHOP_NO, shopNo);Where shopWhere …

C++中关键字volatile和mutable用法

C/C中的volatile关键字和const对应&#xff0c;用来修饰变量&#xff0c;用于告诉编译器该变量值是不稳定的&#xff0c;可能被更改。使用volatile注意事项&#xff1a; (1). 编译器会对带有volatile关键字的变量禁用优化(A volatile specifier is a hint to a compiler that …

基于生成对抗网络(GAN)的人脸变形(附链接) | CSDN博文精选

扫码参与CSDN“原力计划”翻译 | 张一豪校对 | 吴金笛来源 | 数据派THU*点击阅读原文&#xff0c;查看「CSDN原力计划」详细说明。本文详细介绍了生成对抗网络&#xff08;GAN&#xff09;的知识&#xff0c;并用其变换人脸&#xff0c;并探寻如何利用StyleGAN生成不同属性&…

Jmeter连接Oracle数据库

一、Jmeter要连接oracle数据库&#xff0c;就必须复制JDBC驱动jar包文件ojdbc14.jar到Jmeter的lib目录下二、进入Jmeter的bin目录运行Jmeter.bat&#xff0c;启动Jmeter三、Jmeter软件配置如下&#xff1a;1、添加线程组右击线程组&#xff0c;选择“添加--配置元件--JDBC Conn…

swift3.0友盟分享

经过&#xff08;一&#xff09;的讲解&#xff0c;大家应该可以按照友盟提供的测试账号可以集成友盟分享了&#xff0c;友盟目前集合了18个APP共27种分享&#xff0c;可以授权的有10个App&#xff1a;微信、QQ、新浪微博、腾讯微博、人人网、豆瓣、Facebook、Twitter、Linkedi…

C++11中std::future的使用

C11中的std::future是一个模板类。std::future提供了一种用于访问异步操作结果的机制。std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::shared_future相反)( std::future references shared state that is not shared with any other asynchronous retur…

给算法工程师和研究员的「霸王餐」| 附招聘信息

现在的算法工程师真的是太难了&#xff01;要让AI会看人眼都分辨不清的医疗影像&#xff01;数据又不够&#xff0c;还得用前沿技术&#xff01;好不容易学会看片&#xff0c;还要让AI会分析病理&#xff01;然后模型搞出来了&#xff0c;还要把几十种模型&#xff0c;做N次计算…

swift3.0三种反向传值

一 :通知 1.通知传值所用方法 // MARK: - private methods(内部接口) let NotifMycation NSNotification.Name(rawValue:"MyNSNotification") func tempbuttonAction() { //这个方法可以传一个值 NotificationCenter.default.post(name: NotifMycation, object: &q…

C++11中std::shared_future的使用

C11中的std::shared_future是个模板类。与std::future类似&#xff0c;std::shared_future提供了一种访问异步操作结果的机制&#xff1b;不同于std::future&#xff0c;std::shared_future允许多个线程等待同一个共享状态&#xff1b;不同于std::future仅支持移动操作&#xf…

聊聊抖音、奈飞、Twitch、大疆、快手、B站的多媒体关键技术

随着5G牌照发放&#xff0c;5G终端正在迎来集中上市潮&#xff0c;对于5G带来的变革一触即发。目前互联网上超过七成的流量来自多媒体&#xff0c;未来这个比例将超过八成。音视频就像空气和水一样普及&#xff0c;深度到每个人的生活和工作中。同时&#xff0c;深度学习技术则…

Linux安全事件应急响应排查方法总结

Linux安全事件应急响应排查方法总结 Linux是服务器操作系统中最常用的操作系统&#xff0c;因为其拥有高性能、高扩展性、高安全性&#xff0c;受到了越来越多的运维人员追捧。但是针对Linux服务器操作系统的安全事件也非常多的。攻击方式主要是弱口令攻击、远程溢出攻击及其他…

C++11中std::packaged_task的使用

C11中的std::packaged_task是个模板类。std::packaged_task包装任何可调用目标(函数、lambda表达式、bind表达式、函数对象)以便它可以被异步调用。它的返回值或抛出的异常被存储于能通过std::future对象访问的共享状态中。 std::packaged_task类似于std::function&#xff0c…

Swift3.0和OC桥接方法

1.直接在工程中commandn&#xff0c;出现如图&#xff0c;点击Header File创建桥接文件Bridging-Header.h,如图&#xff1a; 2.点击next&#xff0c;出现如图画面&#xff0c;一定要记得勾选第一项&#xff0c;再点击create创建完成。 3.配置桥接文件&#xff0c;点击target - …

量子算命,在线掷筊:一个IBM量子云计算机的应用实践,代码都有了

整理 | Jane 出品| AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; “算命”&#xff0c;古今中外&#xff0c;亘古不衰的一门学问&#xff0c;哪怕到了今天&#xff0c;大家对算命占卜都抱着一些”敬畏“的信任心理&#xff0c;西方流行塔罗牌&#xff0c;国…

rails应用ajax之二:使用rails自身支持

考虑另一种情况&#xff1a; 1. 页面上半部分显示当前的所有用户&#xff0c;页面下半部分是输入新用户的界面&#xff1b; 2. 每当输入新用户时&#xff0c;页面上半部分会动态更新新加用户的内容&#xff1b; 我们还是用ajax实现&#xff0c;不过这次用rails内部对ajax的支持…