JavaScript Day 10
上课日期:2019年8月29日
课程内容
一、JavaScript中的模式
- 工厂模式
function factory() {
var args = arguments;
//实例化对象 返回对象
var obj = new Object();
//封装属性以及方法
obj.name = args[0];
obj.sex = args[1];
obj.age = args[2];
obj.sleep = function () {
return this.name + "会睡觉";
}
return obj;
}
形如以上的这个模式就是工厂模式,即函数里面返回单个对象,在使用时,可以用以下这种形式
var person = factory("HHD", "男", 20);
console.log(person);
输出结果是一个name属性为HHD,sex属性为男,age属性为20,再加上一个sleep方法的对象。
{name: “HHD”, sex: “男”, age: 20, sleep: ƒ}
这种模式的缺点是:没办法区分对象的类型
- 构造函数模式
我们之前常用的就是这种模式,就是直接在函数上写对象,形式如下
function Person() {
this.name = arguments[0];
this.sex = arguments[1];
this.age = arguments[2];
this.eat = function () {
return this.name + "会吃饭!";
}
}
其中,this在正常的js代码中指代的是window,在对象实例化后指代的是当前的对象。
在使用时,可以用如下的方式
var son = new Person("HHD", "男", 20);
console.log(son);
输出结果与上面不同的是
Person {name: “HHD”, sex: “男”, age: 20, eat: ƒ}
前面多了一个Person,即我们定义的类型,这就体现出了这种模式的优点,也就是可以区分类型。
而这个模式的缺点就是每个方法在每个实例上面都需要重新定义一遍。
- 原型模式
这种模式是建立在构造函数模式基础之上的,形式如下
function animal() {
this.name = arguments[0];
this.sex = arguments[1];
this.type = arguments[2]
}
animal.prototype = {
constructor: animal,
eat: function () {
return this.name + "会吃";
},
sleep: function () {
return this.name + "会睡觉";
},
info: function () {
return this.name + "属于:" + this.type + ",性别:" + this.sex;
}
}
在定义函数后可以用prototype进行追加,使用时
var cat = new animal("喵喵", "母", "猫科");
var mouse = new animal("米奇", "公", "鼠科");
console.log(cat, mouse);
输出结果:
animal {name: “喵喵”, sex: “母”, type: “猫科”}
animal {name: “米奇”, sex: “公”, type: “鼠科”}
这种方法的特点是会导致所有的原型属性以及方法全部共享。
- 动态原型模式
这种模式可以通过相关属性动态添加原型 (检测原型是否存在)
function Animal(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.speak = "我会说话";
if (typeof this.speak != "function") {
Animal.prototype.sleep = function () {
console.log(this.name + "在睡觉");
};
}
}
var snack = new Animal("小蛇", 2, '爬');
console.log(snack);
- 单例模式
可以简单理解为返回一个对象
function Instance(name, sex, age) {
var instance = null;
function Animal() {
this.name = arguments[0];
this.sex = arguments[1];
this.age = arguments[2];
}
if (instance == null) {
instance = new Animal(name, sex, age);
}
return instance;
}
var cat = Instance("咪咪", "母", 2);
console.log(cat);
输出结果Animal {name: “咪咪”, sex: “母”, age: 2}
- 模块模式
这种模式类似于代码块的封装
var model = (function () {
var instance = null;
var person = null;
function Animal() {
this.name = arguments[0];
this.sex = arguments[1];
this.age = arguments[2];
}
function Person() {
this.name = arguments[0];
this.sex = arguments[1];
this.age = arguments[2];
}
if (person == null) {
person = new Person("maodou", "男", 18);
}
if (instance == null) {
instance = new Animal("cat", "母", 2);
}
return {
instance: instance,
person: person
}
})()
console.log(model);
输出结果
{instance: Animal, person: Person}
里面有:
instance: Animal {name: “cat”, sex: “母”, age: 2}
person: Person {name: “maodou”, sex: “男”, age: 18}
__ proto __: Object
二、原型链
先写一个Animal构造函数,追加原型对象
function Animal(){
this.name="小猫";
this.sex="母";
}
//原型对象
Animal.prototype={
constructor:Animal,
sleep:function (){
return "会睡觉"
}
}
var cat=new Animal();
console.log(cat)
输出结果为Animal
name: “小猫”
sex: “母”
__ proto__:
constructor: ƒ Animal()
sleep: ƒ ()
__ proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__ defineGetter__: ƒ __ defineGetter__()
__ defineSetter__: ƒ __ defineSetter__()
__ lookupGetter__: ƒ __ lookupGetter__()
__ lookupSetter__: ƒ __ lookupSetter__()
get __ proto__: ƒ __ proto__()
set __ proto__: ƒ __ proto__()
其中,__ proto__就是原型链
三、案例:js实现简易贪吃蛇
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script>
/*
* 画地图
* */
var map;
var snack;
var food;
var times;
function getMap() {
var instance = null;
function Map() {
this.width = 900;
this.height = 600;
this.bgColor = "#000";
this._map = null;
this.createMap = function () {
if (this._map == null) {
this._map = document.createElement("div");
this._map.style.background = this.bgColor;
this._map.style.position = "relative";
this._map.style.height = this.height + "px";
this._map.style.width = this.width + "px";
document.body.appendChild(this._map);
}
}
}
if (instance == null) {
//实例化
instance = new Map();
}
return instance;
}
function getSnack() {
var instance = null;
function Snack() {
this.width = 30;
this.height = 30;
this._snack = [[3, 1, "red", null], [2, 1, "yellow", null], [1, 1, "yellow", null]];
this.direct = "right";
this.createSnack = function () {
for (var i = 0; i < this._snack.length; i++) {
if (this._snack[i][3] == null) {
this._snack[i][3] = document.createElement("div");
this._snack[i][3].style.width = this.width + "px";
this._snack[i][3].style.height = this.height + "px";
this._snack[i][3].style.position = "absolute";
this._snack[i][3].style.background = this._snack[i][2];
map._map.appendChild(this._snack[i][3]);
}
this._snack[i][3].style.left = this._snack[i][0] * this.width + "px";
this._snack[i][3].style.top = this._snack[i][1] * this.height + "px";
}
}
this.snackMove = function () {
//属性传递
var len = this._snack.length - 1;
for (var i = len; i > 0; i--) {
this._snack[i][0] = this._snack[i - 1][0];
this._snack[i][1] = this._snack[i - 1][1];
}
//蛇头移动 方向
switch (this.direct) {
case "right":
this._snack[0][0] += 1;
break;
case "left":
this._snack[0][0] -= 1;
break;
case "up":
this._snack[0][1] -= 1;
break;
case "down":
this._snack[0][1] += 1;
break;
}
//判断蛇有没有吃到食物
if (this._snack[0][0] == food.x && this._snack[0][1] == food.y) {
food.createfood();
this._snack.push([
this._snack[this._snack.length - 1][0],
this._snack[this._snack.length - 1][1],
"yellow",
null
]);
}
//判断蛇穿墙
if (this._snack[0][0] >= 30) {
this._snack[0][0] = 0;
}
if (this._snack[0][0] < 0) {
this._snack[0][0] = 29;
}
if (this._snack[0][1] >= 20) {
this._snack[0][1] = 0;
}
if (this._snack[0][1] < 0) {
this._snack[0][1] = 19;
}
//撞自己撞死
for (var i = 1; i < this._snack.length; i++) {
if (this._snack[0][0] == this._snack[i][0] && this._snack[0][1] == this._snack[i][1]) {
clearInterval(times);
alert("GAME OVER!");
return;
}
}
this.createSnack();
}
}
if (instance == null) {
instance = new Snack();
}
return instance;
}
function getFood() {
var instance = null;
function food() {
this.width = 30;
this.height = 30;
this.bgcolor = "green";
this._food = null;
this.x;
this.y;
this.createfood = function () {
this.x = Math.floor(Math.random() * 30);
this.y = Math.floor(Math.random() * 20);
if (this._food == null) {
this._food = document.createElement("div");
this._food.style.position = "absolute";
this._food.style.width = this.width + "px";
this._food.style.height = this.height + "px";
this._food.style.background = this.bgcolor;
map._map.appendChild(this._food);
}
this._food.style.left = this.x * this.width + "px";
this._food.style.top = this.y * this.height + "px";
}
}
if (instance == null) {
instance = new food();
}
return instance;
}
window.onload = function () {
map = getMap();
map.createMap();
snack = getSnack();
snack.createSnack();
food = getFood();
food.createfood();
times = setInterval(function () {
snack.snackMove();
}, 200);
//按键
document.body.onkeypress = function (e) {
switch (e.key) {
case "w":
if (snack.direct != "down") {
snack.direct = "up";
}
break;
case "a":
if (snack.direct != "right") {
snack.direct = "left";
}
break;
case "d":
if (snack.direct != "left") {
snack.direct = "right";
}
break;
case "s":
if (snack.direct != "up") {
snack.direct = "down";
}
break;
}
}
}
</script>
</body>
</html>