width: 800px;
height: 600px;
background-color: #ccc;
margin: 50px auto;
/蛇和食物的定位需要依赖于地图进行定位,地图需要相对定位,子绝父相/
position: relative;
}
// 分析食物对象:
// 属性
// 1. width 食物的宽度
// 2. height: 食物的高度
// 3. bgc 食物的背景颜色
// 4. x 食物的水平坐标
// 5. y 食物的垂直坐标
// 可以根据食物的坐标计算出来食物的位置信息(left、top值)
// 方法: 能做的事情:
// 根据食物对象的属性把食物创建出来添加到地图中(随机的位置)
// render
function Food(options) {
options = options || {};
this.width = options.width || 20;
this.height = options.height || 20;
this.bgc = options.bgc || “blue”;
this.x = options.x || 0;
this.y = options.y || 0;
// 造成了内存浪费
// this.render = function () {}
}
// 把render 方法添加到Food的原型上
// 好处:
// 1. 所有的食物对象都可以访问到原型上的render方法
// 2. 避免内存浪费
// 参数 target : 目标,把创建的食物元素添加到哪
Food.prototype.render = function(target) {
// 根据食物对象的属性把食物创建出来添加到地图中(随机的位置)
// 面向对象:封装的目的,好复用
// 面向过程:实现功能的
// 1. 创建一个div。div表示食物元素
// 2. div设置样式(width、heigth、、、),样式值来源于实例对象f
// 3. 把div添加到地图上
// 1.
var div = document.createElement(“div”);
// 2.
// 谁调用,指向谁,
// this ==> 实例对象f
div.style.width = this.width + “px”;
div.style.height = this.height + “px”;
div.style.backgroundColor = this.bgc;
// 设置div的位置(left、top)
// 细节问题: left、top必须要有定位才能起到效果
div.style.position = “absolute”;
// 食物的坐标的范围限制:[0, 39]
// 随机得到一个x坐标,x的坐标范围是在 [0, 39]之间,根据x坐标可以计算出来食物的left位置
// 公式:left = x * 食物的宽度
// 随机x坐标
// Math.random() ==> [0, 1)
this.x = parseInt(Math.random() * target.offsetWidth / this.width);
this.y = parseInt(Math.random() * target.offsetHeight / this.height);
// console.log(this.x, this.y);
div.style.left = this.x * this.width + “px”;
div.style.top = this.y * this.height + “px”;
// 3.
target.appendChild(div);
}
// 蛇的代码
// 分析蛇对象
// 属性
// 1. width 一节的宽
// 2. height:一节的高
// 3. headBgc: 蛇头的背景颜色
// 4. bodyBgc: 蛇身体的背景颜色
// 5. 蛇的每一节信息 body
// [
// {x: 2, y: 0}
// {x: 1, y: 0}
// {x: 0, y: 0}
// ]
// 6. direction 蛇的移动方向
// 方法
// render 把蛇渲染到地图上(根据蛇的实例对象去渲染)
// move 蛇移动 采取的是管理蛇头和蛇尾即可
function Snake(options) {
options = options || {};
this.width = options.width || 20;
this.height = options.height || 20;
this.headBgc = options.headBgc || “red”;
this.bodyBgc = options.bodyBgc || “blue”;
this.body = options.body || [
{ x: 2, y: 0 },
{ x: 1, y: 0 },
{ x: 0, y: 0 }
];
this.direction = options.direction || “right”;
}
// 参数target : 表示把创建出来添加到哪去
Snake.prototype.render = function(target) {
// 根据body数组的长度去创建蛇
// this ==> s
for (var i = 0; i < this.body.length; i++) {
// console.log(this.body[i]); // 蛇的每一节信息
var span = document.createElement(“span”);
span.style.width = this.width + “px”;
span.style.height = this.height + “px”;
span.style.position = “absolute”;
span.style.left = this.body[i].x * this.width + “px”;
span.style.top = this.body[i].y * this.height + “px”;
span.style.backgroundColor = i == 0 ? this.headBgc : this.bodyBgc;
target.appendChild(span);
}
}
// 蛇移动
Snake.prototype.move = function(target) {
// 1. 复制当前蛇头,得到一个新的蛇头 叫做 newHead
// 2. 根据蛇的移动方向去确定newHead 的坐标
// 3. 把newHead 添加到body数组,unshift
// 4. 移出掉蛇尾
// 5. body数组每一节的坐标发生了改变,就需要让蛇重新渲染一次。(render)
// 1.
// this ==> s
var newHead = {
x: this.body[0].x,
y: this.body[0].y
}
// 2.
switch (this.direction) {
case “right”:
// 把newHead的x++
newHead.x++;
break;
case “left”:
newHead.x–;
break;
case “up”:
newHead.y–;
break;
case “down”:
newHead.y++;
break;
}
// 3.
this.body.unshift(newHead);
// 4.
this.body.pop();
// 在渲染之前,把地图中的蛇的每一节找到并且移出掉
var spans = target.querySelectorAll(“span”);
for (var i = 0; i < spans.length; i++) {
target.removeChild(spans[i]);
}
// 5.
// 形参和实参是相对的概念:
this.render(target);
// console.log(this.body);
}
6.蛇吃食物
吃食物是属于蛇的方法,应该放到snake.js中的move方法里面
7.蛇撞墙的逻辑
8.撞身体的逻辑
开始游戏
(function(window) {
“use strict”;
// 分析食物对象:
// 属性
// 1. width 食物的宽度
// 2. height: 食物的高度
// 3. bgc 食物的背景颜色
// 4. x 食物的水平坐标
// 5. y 食物的垂直坐标
// 可以根据食物的坐标计算出来食物的位置信息(left、top值)
// 方法: 能做的事情:
// 根据食物对象的属性把食物创建出来添加到地图中(随机的位置)
// render
function Food(options) {
options = options || {};
this.width = options.width || 20;
this.height = options.height || 20;
this.bgc = options.bgc || “blue”;
this.x = options.x || 0;
this.y = options.y || 0;
// 造成了内存浪费
// this.render = function () {}
}
// 把render 方法添加到Food的原型上
// 好处:
// 1. 所有的食物对象都可以访问到原型上的render方法
// 2. 避免内存浪费
// 参数 target : 目标,把创建的食物元素添加到哪
Food.prototype.render = function(target) {
// 根据食物对象的属性把食物创建出来添加到地图中(随机的位置)
// 面向对象:封装的目的,好复用
// 面向过程:实现功能的
// 1. 创建一个div。div表示食物元素
// 2. div设置样式(width、heigth、、、),样式值来源于实例对象f
// 3. 把div添加到地图上
// 1.
var div = document.createElement(“div”);
// 2.
// 谁调用,指向谁,
// this ==> 实例对象f
div.style.width = this.width + “px”;
div.style.height = this.height + “px”;
div.style.backgroundColor = this.bgc;
// 设置div的位置(left、top)
// 细节问题: left、top必须要有定位才能起到效果
div.style.position = “absolute”;
// 食物的坐标的范围限制:[0, 39]
// 随机得到一个x坐标,x的坐标范围是在 [0, 39]之间,根据x坐标可以计算出来食物的left位置
// 公式:left = x * 食物的宽度
// 随机x坐标
// Math.random() ==> [0, 1)
this.x = parseInt(Math.random() * target.offsetWidth / this.width);
this.y = parseInt(Math.random() * target.offsetHeight / this.height);
// console.log(this.x, this.y);
div.style.left = this.x * this.width + “px”;
div.style.top = this.y * this.height + “px”;
// 3.
target.appendChild(div);
}
// 暴露到全局使用
window.Food = Food;
})(window)
(function(window) {
“use strict”;
// 游戏对象,理解成裁判
// 游戏对象能够管理和整个游戏相关的对象(蛇、食物对象、地图对象)
// 属性:
// 1. 蛇对象
// 2. 食物对象
// 3. 地图
// 方法:
// 可以让游戏开始 startGame
// 游戏结束
function Game(target) {
// 把蛇的实例对象添加到游戏对象的snake属性
this.snake = new Snake();
this.food = new Food();
this.map = target;
}
Game.prototype.render = function() {
// 把蛇和食物渲染到地图上
// this ==> g
this.snake.render(this.map);
this.food.render(this.map);
}
Game.prototype.startGame = function() {
var that = this;
// 开启了定时器,让蛇移动起来了
var timerid = setInterval(function() {
// 定时器中的function的this指向了window
// console.log(this);
// 拿到蛇的move方法
that.snake.move(that.map, that.food);
// 添加蛇撞墙的逻辑
// 1. 获取到蛇头的坐标
// 2. 才能做判断
// 获取到蛇头的坐标
var head = that.snake.body[0];
if (
head.x > that.map.offsetWidth / that.snake.width - 1 ||
head.x < 0 ||
head.y < 0 ||
head.y > that.map.offsetHeight / that.snake.height - 1
) {
// 蛇头撞到墙
clearInterval(timerid);
alert(“Game Over!!!”);
}
// 蛇头撞到自己 蛇头坐标和蛇身体坐标
// 注意: i必须从1开始,因为遍历的是蛇的身体
// 这里的i没有必要必须从1开始。i 从4 开始,减少了几次不必要的foe循环
for (var i = 4; i < that.snake.body.length; i++) {
var temp = that.snake.body[i]; // 蛇身体的每一节坐标信息
if (head.x == temp.x && head.y == temp.y) {
clearInterval(timerid);
alert(“Game Over!!!”);
}
};
}, 200);
// 控制蛇移动
document.onkeyup = function(e) {
// console.log(this); // document
var keycode = e.keyCode;
if (keycode == 37) {
// 左
if (that.snake.direction == “right”) {
// 此时蛇正在往右移动
return;
}
that.snake.direction = “left”;
} else if (keycode == 38) {
// 上
if (that.snake.direction == “down”) {
// 此时蛇正在往下移动
return;
}
that.snake.direction = “up”;
} else if (keycode == 39) {
// 右
if (that.snake.direction == “left”) {
// 此时蛇正在往左移动
return;
}
that.snake.direction = “right”;
} else if (keycode == 40) {
// 下
if (that.snake.direction == “up”) {
// 此时蛇正在往上移动
return;
}
that.snake.direction = “down”;
}
}
}
window.Game = Game;
})(window)
(function(window) {
“use strict”;
// 蛇的代码
// 分析蛇对象
// 属性
// 1. width 一节的宽
// 2. height:一节的高
// 3. headBgc: 蛇头的背景颜色
// 4. bodyBgc: 蛇身体的背景颜色
// 5. 蛇的每一节信息 body
// [
// {x: 2, y: 0}
// {x: 1, y: 0}
// {x: 0, y: 0}
// ]
// 6. direction 蛇的移动方向
// 方法
// render 把蛇渲染到地图上(根据蛇的实例对象去渲染)
// move 蛇移动 采取的是管理蛇头和蛇尾即可
function Snake(options) {
options = options || {};
this.width = options.width || 20;
this.height = options.height || 20;
this.headBgc = options.headBgc || “red”;
this.bodyBgc = options.bodyBgc || “blue”;
this.body = options.body || [
{ x: 12, y: 0 },
{ x: 11, y: 0 },
{ x: 10, y: 0 },
{ x: 9, y: 0 },
{ x: 8, y: 0 },
{ x: 7, y: 0 },
{ x: 6, y: 0 },
{ x: 5, y: 0 },
{ x: 4, y: 0 },
{ x: 3, y: 0 },
{ x: 2, y: 0 },
{ x: 1, y: 0 },
{ x: 0, y: 0 }
];
this.direction = options.direction || “right”;
}
// 参数target : 表示把创建出来添加到哪去
Snake.prototype.render = function(target) {
// 根据body数组的长度去创建蛇
// this ==> s
for (var i = 0; i < this.body.length; i++) {
// console.log(this.body[i]); // 蛇的每一节信息
var span = document.createElement(“span”);
span.style.width = this.width + “px”;
span.style.height = this.height + “px”;
span.innerText = i;
span.style.position = “absolute”;
span.style.left = this.body[i].x * this.width + “px”;
span.style.top = this.body[i].y * this.height + “px”;
span.style.backgroundColor = i == 0 ? this.headBgc : this.bodyBgc;
span.style.zIndex = i == 0 ? 999 : 1;
target.appendChild(span);
}
}
// 蛇移动
// 参数food 是食物的实例对象,需要获取到食物的x,y坐标,从而判断蛇有没有迟到食物
Snake.prototype.move = function(target, food) {
// console.log(food); // 食物的实例对象
// 1. 复制当前蛇头,得到一个新的蛇头 叫做 newHead
// 2. 根据蛇的移动方向去确定newHead 的坐标
// 3. 把newHead 添加到body数组,unshift
// 4. 移出掉蛇尾
// 5. body数组每一节的坐标发生了改变,就需要让蛇重新渲染一次。(render)
// 1.
// this ==> s
var newHead = {
x: this.body[0].x,
y: this.body[0].y
}
// 2.
switch (this.direction) {
case “right”:
// 把newHead的x++
newHead.x++;
break;
case “left”:
newHead.x–;
break;
case “up”:
newHead.y–;
break;
case “down”:
newHead.y++;
break;
}
// 蛇吃食物的代码逻辑
// newHead ==> 在这里是最新的坐标,是移动后的坐标
if (newHead.x == food.x && newHead.y == food.y) {
// 蛇吃到食物
// console.log(“蛇吃到食物”);
// 1. 把地图中的食物删除掉,在重新渲染一份添加到地图中
// 2. 把蛇变长一节
// 找到地图中的食物
// 坑: 从整个页面中找到的div是地图
// var div = document.querySelector(“div”);
// console.log(div);
var div = target.querySelector(“div”);
target.removeChild(div);
// 重新渲染食物(render)
food.render(target);
} else {
// 蛇没有吃到食物
// 4.
// 删除蛇尾是有条件的,蛇移动的时候没有吃到食物需要删除掉
this.body.pop();
}
// 3.
this.body.unshift(newHead);
// 在渲染之前,把地图中的蛇的每一节找到并且移出掉
var spans = target.querySelectorAll(“span”);
for (var i = 0; i < spans.length; i++) {
target.removeChild(spans[i]);
}
// 5.
// 形参和实参是相对的概念:
this.render(target);
// console.log(this.body);
}
window.Snake = Snake;
})(window)
1.严格模式规定
2.参考文档
1.混入式继承(mixin)
2.原型链继承
3.Object.create
1.定义函数的三种方式
函数声明
函数表达式
构造函数Function
2.eval函数–了解
3.函数的四种调用模式
函数调用模式
方法调用模式
构造函数调用模式
猜猜看:
//分析思路:1. 看this是哪个函数的 2. 看这个函数是怎么调用的,处于什么调用模式
//题目一:
var age = 38;
var obj = {
age: 18,
getAge: function () {
console.log(this.age);
}
}
var f = obj.getAge;
f();//???
//题目二
var age = 38;
var obj = {
age:18,
getAge:function () {
console.log(this.age);//???
function foo(){
console.log(this.age);//???
}
foo();
}
}
obj.getAge();
obj"getAge";
//题目三:
var length = 10;
var age = 18;
function fn() {
console.log(this.length);
}
var arr = [fn, “222”];
fn();
arr0;
//题目四:
// 面试题5:
var length = 10
function fn() {
console.log(this.length)
}
var obj = {
length: 5,
method: function (fn) {
fn()
arguments0;
}
}
obj.method(fn, 10, 5);
上下文调用模式
call方法
伪数组与数组
apply方法
bind方法
函数是由new Function创建出来的,因此函数也是一个对象, 所有的函数都是new Function的实例。
1.函数的原型链结构
2.Function.prototype成员
3.完整版原型链
1.作用域链
2.作用域链练习
1.闭包的基本概念
闭包(closure)是JavaScript语言的一个难点,也是JavaScript的一个特色,很多高级的应用都要依靠闭包来实现。