之前闲时开发过一个简单的网页版贪食蛇游戏程序,现在把程序的实现思路写下来,供有兴趣同学参考阅读。

代码的实现比较简单,整个程序由三个类,一组常量和一些游戏逻辑以外的初始化和控制代码组成,总共400多行JavaScript。

游戏中的三个类分别是「组成蛇身体的节点」「蛇」「贪食蛇游戏」的抽象,常量用来表示游戏中的各种状态。

先从常量讲起

  1. var TRANSVERSE = 30;
  2. var VERTICAL = 40;
  3.  
  4. var LEFT = 1;
  5. var RIGHT = 2;
  6. var TOP = 3;
  7. var BOTTOM = 4;
  8.  
  9. var GAME_START = 1;
  10. var GAME_STOP = 2;
  11. var GAME_OVER = 3

首先,可以把游戏的逻辑想象成一个不断变换的数据结构,把游戏的界面想象成由一组像素格子组成的长方形,界面渲染程序定时读取游戏数据结构,将数据结构中不同的值表示成不同的颜色并画在游戏界面上。

因此,常量TRANSVERSEVERTICAL分别代表游戏数据结构的最大边界,也就是游戏界面横向和纵向的像素点个数。

常量LEFT、RIGHT、TOP、BOTTOM分别代表贪食蛇上下左右的走向

常量GAME_START、GAME_STOP、GAME_OVER代表游戏的三个状态,游戏进行中、游戏暂停中、游戏结束

游戏中的三个类是游戏的逻辑实现,相对复杂

贪食蛇蛇身由一系列相互引用的节点组成,是一个链表结构,如下图

每一个节点是SnakeNode类的一个实例

  1. //组成蛇的节点,一个链表结构
  2. var SnakeNode = function(point) {
  3. var prevDirection, currDirection,
  4. next,
  5. pos = point;
  6.  
  7. //获得下一个
  8. this.getNext = function() {
  9. return next;
  10. }
  11.  
  12. //设置下一个
  13. this.setNext = function(el) {
  14. next = el;
  15. }
  16.  
  17. //设置方向
  18. this.setDirection = function(value) {
  19. currDirection = value;
  20. }
  21.  
  22. //获得方向
  23. this.getDirection = function() {
  24. return currDirection;
  25. }
  26.  
  27. //计算结点下一个位置
  28. this.computePosition = function() {
  29. pos = SnakeNode.getNextPoint( pos, currDirection );
  30. if( next ) {
  31. next.computePosition();
  32. }
  33. if( prevDirection != currDirection ) {
  34. prevDirection = currDirection;
  35. if( next ){
  36. next.setDirection(currDirection);
  37. }
  38. }
  39. }
  40.  
  41. //获得位置
  42. this.getPosition = function(){
  43. return pos;
  44. }
  45. }
  46.  
  47. //通过方向计算相对与当前位置的下一个位置
  48. SnakeNode.getNextPoint = function (point, direction)
  49. {
  50. var newPoint = {};
  51. switch(direction)
  52. {
  53. case LEFT:
  54. newPoint.x = point.x - 1;
  55. newPoint.y = point.y ;
  56. break;
  57. case RIGHT:
  58. newPoint.x = point.x + 1;
  59. newPoint.y = point.y;
  60. break;
  61. case TOP:
  62. newPoint.x = point.x;
  63. newPoint.y = point.y - 1;
  64. break;
  65. case BOTTOM:
  66. newPoint.x = point.x;
  67. newPoint.y = point.y + 1;
  68. break;
  69. }
  70. return newPoint;
  71. }

蛇身节点有四个属性

prevDirection 上一次移动时的蛇身走向

currDirection 当前蛇身走向

next 节点的下一个节点

pos 节点的位置

六个方法

getNext 获得节点的下一个节点

setNext 设置节点的下一个节点

setDirection 设置节点的方向

getDirection 获得节点的方向

computePosition 计算节点移动后的目标位置

getPosition 获得节点的位置

SnakeNode.getNextPoint 这个方法是一个静态方法, 不属于节点实例, 它的功能是根据方向计算出某一个坐标的下一个坐标, 比如说10和10是某个节点当前的坐标, 那么它向左移动一个单位后坐标就是9和10;向右移动一个单位后坐标就是11和10,同理向上和向下坐标分别是10,9和10,11。

computePosition需要特点说明一下,它在计算出自身移动后的目标位置以后,还会调用它引用的下一个节点的 computePosition方法,然后下一个节点再次执行相同的操作,一直到蛇身的最后一个节点为止,这就是链表的特性。同时如果方向发了变化,这个方法还会把当前节点的方向同步给它引用的下一个节点,就是靠这一点, 蛇身每一个节点的走向才能一致。

通过这一系列属性和方法就能表示出蛇身的节点特性了。

Snake是整条蛇的抽象表示,代码如下

  1. //蛇
  2. var Snake = function( head ) {
  3. var snake = head;
  4. var isGameover = false;
  5. var self = this;
  6.  
  7. //为蛇增加一个节点
  8. this.addNode = function() {
  9. var lastNode = getLastNode();
  10. var point = lastNode.getPosition();
  11. var reverse;
  12. switch(lastNode.getDirection()) {
  13. case LEFT:
  14. reverse = RIGHT;
  15. break;
  16. case RIGHT:
  17. reverse = LEFT;
  18. break;
  19. case TOP:
  20. reverse = BOTTOM;
  21. break;
  22. case BOTTOM:
  23. reverse = TOP;
  24. break;
  25. }
  26. var newPoint = SnakeNode.getNextPoint(point, reverse);
  27. var node = new SnakeNode(newPoint);
  28. node.setDirection(lastNode.getDirection());
  29. lastNode.setNext(node);
  30. }
  31.  
  32. //获所所有蛇节点的位置
  33. this.getAllNodePos = function() {
  34. var posList = new Array;
  35. var node = snake;
  36. do{
  37. posList.push(node.getPosition());
  38. node = node.getNext();
  39. }while(node);
  40. return posList;
  41. }
  42.  
  43. //获得蛇长度
  44. this.getLength = function() {
  45. var count = 0;
  46. var node = snake;
  47. while(node) {
  48. count ++;
  49. node = node.getNext();
  50. }
  51. return count;
  52. }
  53.  
  54. //游戏是否结束
  55. this.isGameover = function() {
  56. return isGameover;
  57. }
  58. //移动
  59. this.move = function() {
  60. if (!isGameover) {
  61. snake.computePosition();
  62. }
  63. checkGameover();
  64. }
  65. //根据方向导航
  66. this.setDirection = function (direction) {
  67. if( !isGameover ) snake.setDirection(direction);
  68. }
  69. //获得蛇头位置
  70. this.getHeadPos = function() {
  71. return snake.getPosition();
  72. }
  73. //获得蛇头方向
  74. this.getHeadDirection = function() {
  75. return snake.getDirection();
  76. }
  77. var checkGameover = function() {
  78. var l = snake.getPosition();
  79. var cl = self.getAllNodePos();
  80. if(l.x < 0 || l.x >= TRANSVERSE || l.y < 0 || l.y >= VERTICAL ) {
  81. isGameover = true;
  82. return;
  83. }
  84. for(var i = 0 ; i < cl.length ; i ++) {
  85. if(l != cl[i] && cl[i].x == l.x && cl[i].y == l.y) {
  86. isGameover = true;
  87. return;
  88. }
  89. }
  90. }
  91.  
  92. var getLastNode = function() {
  93. var node = snake.getNext();
  94. while( node ){
  95. var nextNode = node.getNext();
  96. if(!nextNode) return node;
  97. node = nextNode;
  98. }
  99. return snake;
  100. }
  101. }

这个类有三个属性

snake是蛇的脑袋节点,因为是一个链表,所以通过蛇的脑袋就可以访问到蛇的尾巴,因此,蛇的脑袋就可以表示一条蛇了。

isGameover游戏是否结束

self是实例自身的引用,跟游戏逻辑的表示没有任何关系。

八个公有方法

addNode 给蛇身增加一个结点,当蛇吃到食物时会调用这个方法,这个方法会把新的节点追加到最后一个节点(蛇尾)的后面。其中局部变量reverse是用来计算新节点的位置用的,假如当前节点的方向是向右的,那么下一个节点肯定在当前节点的左边,以此类推, reverse变量就是当前节点相反方向的值,细节请结合代码理解。

getAllNodePos 获得蛇身所有节点的位置。

getLength 获得蛇身长度(蛇身节点个数)

isGameover 游戏是否结束

move 移动蛇身,调用一次整个蛇身便移动一下,这里的移动仅仅是数据结构变化,具体效果需要将数据结构结果渲染至页面。

setDirection 设置蛇的游动方向

getHeadPos 获得蛇身的第一个节点(蛇头)的位置

getHeadDirection 获得蛇(蛇头)游动的方向

二个私有方法

checkGameover 检查游戏是否结束,分别检测游戏的第一个节点是否落在 TRANSVERSEVERTICAL常量定义的范围之外(撞墙)和是否落在蛇身节点的位置之上(咬到自己)。

getLastNode 获得蛇身的最后一个结果

通过SnakeNodeSnake这两个类,便抽象出了贪食蛇的结构和特性,但是现在这条蛇只是一个逻辑结构,是不会动的, 更不能玩。接下来我们便让这条蛇游动起来, 还可以控制它的方向, 让它去觅食并越长越长越游越快。

  1. //贪食蛇游戏
  2. var SnakeGame = function() {
  3. var snake ;
  4. var moveTimer, randomTimer;
  5. var currDirection;
  6. var foods = [];
  7. var status = GAME_STOP;
  8. var context;
  9.  
  10. var self = this;
  11.  
  12. this.onEatOne = function(){};
  13.  
  14. var getRandom = function(notin) {
  15. var avaiable = [];
  16. for(var y = 0 ; y < VERTICAL ; y ++)
  17. {
  18. for(var x = 0 ; x < TRANSVERSE; x++ ) {
  19. var j = 0;
  20. var avaiableFlag = true;
  21. while( j < notin.length ){
  22. var el = notin[j];
  23. if( el.x == x && el.y == y ) {
  24. notin.splice(j,1);
  25. avaiableFlag = false;
  26. break;
  27. }
  28. j++;
  29. }
  30. if(avaiableFlag) avaiable.push({ x: x , y: y });
  31. }
  32. }
  33. var rand = Math.floor(Math.random() * avaiable.length);
  34. return avaiable[rand];
  35. }
  36.  
  37. //导航
  38. var navigate = function(direction) {
  39. var sd = snake.getHeadDirection();
  40. var d ;
  41. if((sd == LEFT || sd == RIGHT) && (direction == TOP || direction == BOTTOM)) d = direction;
  42. if((sd == TOP || sd == BOTTOM) && (direction == LEFT || direction == RIGHT)) d = direction;
  43. if(d) currDirection = d;
  44. }
  45.  
  46. var move = function() {
  47. moveTimer = window.setTimeout( move, computeMoveInterval() );
  48. if(currDirection) snake.setDirection( currDirection );
  49. snake.move();
  50. var lc = snake.getHeadPos();
  51. for(var i = 0 ; i < foods.length ; i ++) {
  52. if(lc.x == foods[i].x && lc.y == foods[i].y) {
  53. snake.addNode();
  54. self.onEatOne();
  55. foods.splice( i, 1 );
  56. break;
  57. }
  58. }
  59. if(snake.isGameover()){
  60. gameover();
  61. return;
  62. }
  63. draw();
  64. }
  65.  
  66. var createFood = function() {
  67. var notin = snake.getAllNodePos().concat(foods);
  68. var rand = getRandom(notin);
  69. foods.push(rand);
  70. }
  71.  
  72. var arrayToMap = function(array) {
  73. var map = {};
  74. for(var i = 0 , point ; point = array[i++];) map[[point.x , point.y]] = null;
  75. return map;
  76. }
  77.  
  78. //获得当前游戏数据结构
  79. var getMap = function() {
  80. var board = new Array;
  81. for (var y = 0 ; y < VERTICAL; y++) {
  82. for (var x = 0 ; x < TRANSVERSE ; x++) {
  83. board.push({ x: x, y: y });
  84. }
  85. }
  86. var cl = snake.getAllNodePos();
  87. var food = arrayToMap(foods);
  88. cl = arrayToMap(cl);
  89. board = arrayToMap(board);
  90. for(var key in cl) board[key] = 'snake';
  91. for(var key in food) board[key] = 'food';
  92. return board;
  93. }
  94.  
  95. //获得分数
  96. this.getScore = function() {
  97. return snake.getLength() - 1;
  98. }
  99.  
  100. //获得级别
  101. this.getLevel = function() {
  102. var score = self.getScore();
  103. var level = 0;
  104. if(score <= 5) level = 1;
  105. else if(score <= 12) level = 2;
  106. else if(score <= 22) level = 3;
  107. else if(score <= 35) level = 4;
  108. else if(score <= 50) level = 5;
  109. else if(score <= 75) level = 6;
  110. else if(score <= 90) level = 7;
  111. else if(score <= 100) level = 8;
  112. else level = 9;
  113. return level;
  114. }
  115.  
  116. var computeMoveInterval = function() {
  117. var speed = {
  118. '1':200,
  119. '2':160,
  120. '3':120,
  121. '4':100,
  122. '5':80,
  123. '6':60,
  124. '7':40,
  125. '8':20,
  126. '9':10
  127. }
  128. var level = self.getLevel();
  129. return speed[level];
  130. }
  131.  
  132. var gameover = function () {
  133. status = GAME_OVER;
  134. window.clearTimeout(moveTimer);
  135. window.clearInterval(foodTimer);
  136. unBindEvent();
  137. alert('游戏结束');
  138. }
  139.  
  140. //获得游戏状态
  141. this.gameState = function () {
  142. return status;
  143. }
  144.  
  145. //游戏开始
  146. this.start = function() {
  147. status = GAME_START;
  148. moveTimer = window.setTimeout(move , computeMoveInterval());
  149. foodTimer = window.setInterval(createFood, 5000);
  150. bindEvent();
  151. }
  152.  
  153. //暂停游戏
  154. this.stop = function() {
  155. status = GAME_STOP;
  156. window.clearTimeout(moveTimer);
  157. window.clearInterval(foodTimer);
  158. unBindEvent();
  159. }
  160.  
  161. this.initialize = function( canvasId ) {
  162. var head = new SnakeNode({ x: Math.ceil(TRANSVERSE / 2), y: Math.ceil(VERTICAL / 2) });
  163. head.setDirection([LEFT, RIGHT , TOP , BOTTOM][Math.floor(Math.random() * 4)])
  164. snake = new Snake(head);
  165.  
  166. var canvas = document.getElementById(canvasId);
  167. context = canvas.getContext('2d');
  168. }
  169.  
  170. //画界面
  171. var draw = function () {
  172. context.fillStyle = '#fff';
  173. context.fillRect(0, 0, 300, 400);
  174. var map = getMap();
  175. for (var key in map) {
  176. var pointType = map[key];
  177. var x = key.split(',')[0];
  178. var y = key.split(',')[1];
  179.  
  180. if (pointType == 'snake') {
  181. context.fillStyle = '#000';
  182. } else if (pointType == 'food') {
  183. context.fillStyle = '#f00';
  184. } else {
  185. continue;
  186. }
  187. context.fillRect( x * 10, y * 10, 10, 10 );
  188. }
  189. }
  190.  
  191. //绑定事件
  192. var bindEvent = function () {
  193. document.body.onkeydown = function (e) {
  194. e = e || window.event;
  195. var keyCode = e.keyCode;
  196. switch (keyCode) {
  197. case 37:
  198. navigate(LEFT);
  199. break;
  200. case 38:
  201. navigate(TOP);
  202. break;
  203. case 39:
  204. navigate(RIGHT);
  205. break;
  206. case 40:
  207. navigate(BOTTOM);
  208. break;
  209. }
  210. }
  211. }
  212.  
  213. //取消绑定
  214. var unBindEvent = function () {
  215. document.body.onkeydown = null;
  216. }
  217. }

SnakeGame类算不上某一种结构抽象, 它仅仅是一组功能的封装, 其中包括人机交互事件、将数据结构转换成界面和一系列组成游戏的功能。此类比较复杂,就不以讲解之前两个类的方法讲解了。我们从类的实例化为入口开始讲解,然后再逐步扩展至类中的其它方法和属性。

var game = new SnakeGame();

实例化对象,调用构造函数后,类的几个属性被声明或初始化。

  1. var snake ;
  2. var moveTimer, randomTimer;
  3. var currDirection;
  4. var foods = [];
  5. var status = GAME_STOP;
  6. var context;
  7.  
  8. var self = this;
  9.  
  10. this.onEatOne = function(){};

snake 也就是Snake类的实例

moveTimer 使蛇身运动的setTimeout函数的返回值, clearTimeout此值后,表示游戏暂停

randomTimer 随机产生食物的setInterval函数的返回值,clearInterval后停止生成食物,表示游戏暂停

foods 食物,因为会有多个食物产生,因为初始化为数组来存放食物

status 游戏状态,初始化状态为暂停中

context 游戏界面的canvas对象

self 没有表示实例自身, 跟游戏不相关

onEatOne 并不是属性, 而是游戏的一个事件, 当蛇吃到食物时, 此函数(事件)会被调用以用来通知监听者

game.initialize("snake");

初始化游戏,initialize方法的参数是游戏界面的canvas的元素ID,这个方法的细节如下

  1. this.initialize = function( canvasId ) {
  2. var head = new SnakeNode({ x: Math.ceil(TRANSVERSE / 2), y: Math.ceil(VERTICAL / 2) });
  3. head.setDirection([LEFT, RIGHT , TOP , BOTTOM][Math.floor(Math.random() * 4)])
  4. snake = new Snake(head);
  5.  
  6. var canvas = document.getElementById(canvasId);
  7. context = canvas.getContext('2d');
  8. }

执行的操作分别是

  1. 实例化蛇的第一个节点,事实上刚开始也只有一个节点,位置设置在界面的中间。

  2. 随机生成一个方向并设置

  3. 实例化Snake类,以head(第一个节点)作为构造函数参数

  4. 引用canvas,获取canvascontext对象

至此,游戏已经初始化完成,然而,此刻的游戏是静止的,我们还需要调用start方法让游戏开始

  1. this.start = function() {
  2. status = GAME_START;
  3. moveTimer = window.setTimeout(move , computeMoveInterval());
  4. foodTimer = window.setInterval(createFood, 5000);
  5. bindEvent();
  6. }

此方法执行的操作分别是

  1. 将游戏的状态设置成 GAME_START常量的值(表示游戏开始)

  2. 让蛇身持续移动

  3. 每5秒生成一个食物

  4. 绑定交互事件,也就是我们用键盘的方向键上下左右控制蛇游动的方向的事件

先看被setTimeout调用的move方法

  1. var move = function() {
  2. moveTimer = window.setTimeout( move, computeMoveInterval() );
  3. if(currDirection) snake.setDirection( currDirection );
  4. snake.move();
  5. var lc = snake.getHeadPos();
  6. for(var i = 0 ; i < foods.length ; i ++) {
  7. if(lc.x == foods[i].x && lc.y == foods[i].y) {
  8. snake.addNode();
  9. self.onEatOne();
  10. foods.splice( i, 1 );
  11. break;
  12. }
  13. }
  14. if(snake.isGameover()){
  15. gameover();
  16. return;
  17. }
  18. draw();
  19. }
  1. 方法里面还有一次setTimeout调用,起的到作用和setInterval相同

  2. 设置蛇游动的方向

  3. 调用蛇的move方法移动

  4. 获得蛇头的位置,检查它是否与物品的位置重叠,假如重叠那么表示蛇吃到了食物,因为会调用蛇的addNode方法为蛇增加一个结点,并且触发onEatOne事件用来通知外部的事件监听,再将初吃掉的食物从食物列表中拿掉

  5. 判断游戏是否结束,假如没结束那么就执行draw方法将数据结果渲染至游戏界面

再来看 computeMoveInterval 方法,这个方法是setTimeout的第二个参数,在这里表达的意思就是定时执行move方法的时间间隔。

  1. var computeMoveInterval = function() {
  2. var speed = {
  3. '1':200,
  4. '2':160,
  5. '3':120,
  6. '4':100,
  7. '5':80,
  8. '6':60,
  9. '7':40,
  10. '8':20,
  11. '9':10
  12. }
  13. var level = self.getLevel();
  14. return speed[level];
  15. }

随着游戏的进行,游戏的级别会增加,随着级别增加, 这个值越小, 也就是说move方法被执行的频率就越高,因此蛇游动的速度会越快, 游戏难度也就越大。

createFood每5秒被调用一次生成一个食物

  1. var createFood = function() {
  2. var notin = snake.getAllNodePos().concat(foods);
  3. var rand = getRandom(notin);
  4. foods.push(rand);
  5. }

蛇身体所占的位置和已有食物的位置被排除掉,显然食物不能生成在已被占用的位置上。

最后,我们来讲一下draw方法,它的作用是将游戏的数据结构转换为可视化界面

  1. var draw = function () {
  2. context.fillStyle = '#fff';
  3. context.fillRect(0, 0, 300, 400);
  4. var map = getMap();
  5. for (var key in map) {
  6. var pointType = map[key];
  7. var x = key.split(',')[0];
  8. var y = key.split(',')[1];
  9.  
  10. if (pointType == 'snake') {
  11. context.fillStyle = '#000';
  12. } else if (pointType == 'food') {
  13. context.fillStyle = '#f00';
  14. } else {
  15. continue;
  16. }
  17. context.fillRect( x * 10, y * 10, 10, 10 );
  18. }
  19. }

将游戏结构转换成draw方法可用的数据结构还需要调用两个方法,分别是getMaparrayToMap

  1. var arrayToMap = function(array) {
  2. var map = {};
  3. for(var i = 0 , point ; point = array[i++];) map[[point.x , point.y]] = null;
  4. return map;
  5. }
  6.  
  7. var getMap = function() {
  8. var board = new Array;
  9. for (var y = 0 ; y < VERTICAL; y++) {
  10. for (var x = 0 ; x < TRANSVERSE ; x++) {
  11. board.push({ x: x, y: y });
  12. }
  13. }
  14. var cl = snake.getAllNodePos();
  15. var food = arrayToMap(foods);
  16. cl = arrayToMap(cl);
  17. board = arrayToMap(board);
  18. for(var key in cl) board[key] = 'snake';
  19. for(var key in food) board[key] = 'food';
  20. return board;
  21. }

arrayToMap的作用其实是将一个一维数组转换为二维数组(并不是真正的二维数组,但是为了方便表达就借用二维数组这种结构),只是JavaScript的二维数组表示的有点奇葩,是一个map,所以这个函数的名称就被命名为arrayToMap

getMap函数的逻辑如下

  1. 建一个二维数组,元素个数等于TRANSVERSE * VERTICAL

  2. 获取蛇身所占的位置列表,转换成二维数组

  3. 获得食物所占的位置列表,转换成二维数组

  4. 通过null、snake、food三种值区分空、蛇身节点、食物

最终的数组结构从可视的角度来表示大概是这个样子

[null,null,null,null,null,

null,null,null,food,null,

null,null,null,null,null,

null,null,food,null,null,

null,null,snake,snake,null,

null,null,snake,null,null]

这个结构会随着move方法的调用而不断变化, draw方法就不断的将数据结构渲染至canvas上,整条蛇因此也就动了起来。

最后我们来看bindEvent方法

  1. var bindEvent = function () {
  2. document.body.onkeydown = function (e) {
  3. e = e || window.event;
  4. var keyCode = e.keyCode;
  5. switch (keyCode) {
  6. case 37:
  7. navigate(LEFT);
  8. break;
  9. case 38:
  10. navigate(TOP);
  11. break;
  12. case 39:
  13. navigate(RIGHT);
  14. break;
  15. case 40:
  16. navigate(BOTTOM);
  17. break;
  18. }
  19. }
  20. }

这个方法很简单,就是用来监听方向键的事件,然后控制蛇的方向以达到操作游戏的效果。

至此,整个游戏的逻辑也就开发完成了。麻雀虽小,但五脏俱全,这个游戏玩法虽然很少,但确实是一个正儿八经的贪食蛇游戏。附上可运行的源代码的链接地址

http://pan.baidu.com/s/1o7VIcWy

就一个html文件

游戏是我多年前写的,代码略显青涩,函数和变量的命名也是词不达意,但大致意思能表达清楚,大家就将就着看吧。

JavaScript贪食蛇游戏制作详解的更多相关文章

  1. javascript中=、==、===区别详解

    javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...

  2. Javascript 调试利器 Firebug使用详解

    Javascript 调试利器 Firebug使用详解 有时候,为了更清楚方便的查看输出信息,我们可能需要将一些调试信息进行分组输出,那么可以使用console.group来对信息进行分组,在组信息输 ...

  3. JavaScript中return的用法详解

    JavaScript中return的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 t ...

  4. javascript 中合并排序算法 详解

    javascript 中合并排序算法 详解 我会通过程序的执行过程来给大家合并排序是如何排序的...  合并排序代码如下: <script type="text/javascript& ...

  5. javascript中的this作用域详解

    javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...

  6. JavaScript中this的用法详解

    JavaScript中this的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 thi ...

  7. 高性能JavaScript模板引擎实现原理详解

    这篇文章主要介绍了JavaScript模板引擎实现原理详解,本文着重讲解artTemplate模板的实现原理,它采用预编译方式让性能有了质的飞跃,是其它知名模板引擎的25.32 倍,需要的朋友可以参考 ...

  8. JavaScript对象的property属性详解

    JavaScript对象的property属性详解:https://www.jb51.net/article/48594.htm JS原型与原型链终极详解_proto_.prototype及const ...

  9. javascript常用经典算法实例详解

    javascript常用经典算法实例详解 这篇文章主要介绍了javascript常用算法,结合实例形式较为详细的分析总结了JavaScript中常见的各种排序算法以及堆.栈.链表等数据结构的相关实现与 ...

随机推荐

  1. javaweb log4j显示完整sql日志

    javaweb显示完整sql日志 所需jar包: log4j-1.2.17.jar log4jdbc-1.2.jar slf4j-api-1.7.12.jar slf4j-log4j12-1.7.12 ...

  2. java byte【】数组与文件读写

    此文全文参考http://blog.csdn.net/sniffer_wang/article/details/7455701,自己加以改进应用,谢了 import java.io.ByteArray ...

  3. matlab 嵌套循环的学习

    循环嵌套带嵌套的循环一般为两重,举例1: disp('一个简单的二重for循环'); : : result = ii *jj ; fprintf(' %d * %d = %d \n',ii,jj,re ...

  4. 使用node-inspector调试nodejs程序<nodejs>

    1.npm install -g node-inspector  // -g 导入安装路径到环境变量 一般是c盘下AppData目录下 2.node-inspector & //启动node- ...

  5. PowerPoint超链接字体颜色修改、怎么去掉超链接下划线

    经常在做PPT幻灯片时会遇到这样一个问题,给文字加超链接后发现链接的颜色是蓝色的,而且还带有下划线,这种效果与主题的色彩搭配简直是太影响美观效果了.有没有什么办法可以去掉PPT中的超链接下划线?再将超 ...

  6. Web前端浏览器兼容问题

    所谓的浏览器兼容性问题,是指因为不同的浏览器对同一段代码有不同的解析,造成页面显示效果不统一的情况.在大多数情况下,我们的需求是,无论用户用什么浏览器来查看我们的网站或者登陆我们的系统,都应该是统一的 ...

  7. Spring+SpringMVC+MyBatis+easyUI整合基础篇(二)牛刀小试

    承接上文,该篇即为项目整合的介绍了. 废话不多说,先把源码和项目地址放上来,重点要写在前面. github地址为ssm-demo 你也可以先体验一下实际效果,点击这里就行啦 账号:admin 密码:1 ...

  8. 从源码解析LinkedList集合

         上篇文章我们介绍了ArrayList类的基本的使用及其内部的一些方法的实现原理,但是这种集合类型虽然可以随机访问数据,但是如果需要删除中间的元素就需要移动一半的元素的位置,效率低下.并且它内 ...

  9. DAX/PowerBI系列 - 写在前面

    今天讲的主角是: 不过,先上一个图--2017 Gartner商业智能和数据分析魔力象限 DAX关注这个玩意儿有好一段时间了,刚开始的时候(2014年?)是从Excel里面认识的.2014年当时公司用 ...

  10. SQLDataSet中执行DDL语句

    在SQLDataSet中执行我们输入的DDL语句,并观察执行结果. 这里为了省输入的时间,从先输好的记事本中复制的SQL语句.效果图: ******************************** ...