当面试官问你了不了解defineProperty的时候。。。

栏目: JavaScript · 发布时间: 6年前

内容简介:在当前的前端环境下,vue这种框架可以算是一项基础技能,可以说不会vue很难找到工作,而且大多数的面试官都很喜欢问的一个问题就是,关于vue的双向数据绑定原理,这个问题可以说是耳熟能详了,那抛开vue的设计思路,单单就是这是一个非常简单的贪吃蛇的小游戏(请忽略里面非常多的细节bug。。。),这个小游戏就是通过defineProperty这个api实现的。这个api的一些属性就不多介绍了,相信大家都知道。首先,先要分析一下这个游戏,主体的组成成分就是三个类,背景,食物,和蛇,剩下的就是那个开始按钮,暂且不管。

在当前的前端环境下,vue这种框架可以算是一项基础技能,可以说不会vue很难找到工作,而且大多数的面试官都很喜欢问的一个问题就是,关于vue的双向数据绑定原理,这个问题可以说是耳熟能详了,那抛开vue的设计思路,单单就是 Object.defineProperty() 这个api的话,说你写过这个就够了。

当面试官问你了不了解defineProperty的时候。。。

这是一个非常简单的贪吃蛇的小游戏(请忽略里面非常多的细节bug。。。),这个小游戏就是通过defineProperty这个api实现的。这个api的一些属性就不多介绍了,相信大家都知道。

首先,先要分析一下这个游戏,主体的组成成分就是三个类,背景,食物,和蛇,剩下的就是那个开始按钮,暂且不管。接下来就开始一个一个来看,先说背景,这个背景可以看成是一个类似于棋盘的东西,既然是棋盘就可以把它当成一个平面直角坐标系构成的网格,

当面试官问你了不了解defineProperty的时候。。。

然后这个网格就可以看成是一个二维数组,这样就可以对应坐标了,既然要用defineProperty,所以每一项都要是个对象。好,背景这个类大概的功能就是这样了。

class Qipan {
	constructor(w, h, id){
		this.w = w
		this.h = h
		this.box = document.getElementById(id)
	}
	init(){
		var tpl = "<ul class='point clearfix'>"
		var tem = ''
		for (var i = 0;i < this.w;i++) {
			tpl += '<li></li>'
		}
		tpl += '</ul>'
		for(var j = 0;j < this.h;j++){
			tem += tpl
		}
		this.box.innerHTML = tem
		this.box.style.width = 20 * this.w +'px'
	}
	getQi () {
		var arr = []
		for (var i = 0;i < this.h; i++) {
			arr.push(new Array())
			for (var j = 0;j < this.w;j++){
				arr[i].push({flag : false,newFlag: '', site:[i, j]})
			}
		}
		return arr
	}
}
复制代码

接下来就要开始劫持每个格子对应的对象的key。

function observer(arr) {
	arr.forEach(arr1 => {
		arr1.forEach( item => {
			Object.defineProperty(item,'flag',{
				enumerable: true,
				configurable: true,
				get: ()=>{
					return item.newFlag
				},
			  	set:newVal=> {
			  		if (newVal === 'snake') {
			            document.getElementsByClassName('point')[item.site[0]].getElementsByTagName('li')[item.site[1]].style.background = '#DB7093'
			  			item.newFlag = 'snake'
			  		} else if (newVal === 'food') {
			  			document.getElementsByClassName('point')[item.site[0]].getElementsByTagName('li')[item.site[1]].style.background = 'red'
			  			item.newFlag = 'food'
			  		} else {
			  			item.newFlag = ''
			  			document.getElementsByClassName('point')[item.site[0]].getElementsByTagName('li')[item.site[1]].style.background = '#F5DEB3'
			  			
			  		}
		        }
			})
		})
	})
}
复制代码

介绍一下里面的参数

configurable

当且仅当该属性的configurable为true时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。

enumerable

当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为 false。

数据描述符同时具有以下可选键值: value

该属性对应的值。可以是任何有效的JavaScript值(数值,对象,函数等)。默认为 undefined。

writable

当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false。 存取描述符同时具有以下可选键值:

get

一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。 默认为 undefined。

set

一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。默认为 undefined。

(摘自MDN)

这里我们监听的属性为flag,flag表示的就是当前这个网格是哪个对象所处的位置,如果是食物处于这个位置,那这个flag就是food,当这个字段改变的时候,根据这个字段来判断,这个位置的状态,并作出相应的改变。

再来分析第二个类,蛇,这个类应该具有的功能,初始化,移动,吃食物,变长,死亡。这里初始化和死亡可以看成是一个方法,这里的移动就要根据上下左右和速度前进,吃食物和变长简单理解就是下一个前进的格子如果食物的话,就直接变成蛇的一部分就好了。

class Snake {
	constructor(qipan,h,food){
		this.qipan = qipan
		this.h = h
		this.h2 = JSON.parse(JSON.stringify(h))
		this.direct = 'left'
		this.que = []
		this.food = food
	}
	init () {
		this.qipan.forEach(item=>{
			item.forEach(items=>{
				items.flag = ''
			})
		})
        this.direct = 'left'
		
		if (this.que.length !== 0) {
			this.h = JSON.parse(JSON.stringify(this.h2))
			this.que = []
			clearInterval(time)
			time = null
		} 
			this.qipan[this.h[0]][this.h[1]].flag = 'snake'
			this.qipan[this.h[0]][this.h[1] + 1].flag = 'snake'
			this.que.push(this.qipan[this.h[0]][this.h[1]])
			this.que.push(this.qipan[this.h[0]][this.h[1] + 1])
		
	}
	getUp(){
		this.direct = 'up'
	}
	getLeft() {
		this.direct = 'left'
	}
	getRight(){
		this.direct = 'right'
	}
	getDown(){
		this.direct = 'down'
	}
	getGo (){
		var _this = this
		switch (this.direct) {
			case 'left':
                if (this.qipan[this.h[1] - 1]) {
                    wooDir(this.qipan[this.h[0]][this.h[1] - 1],'left')
                } else {
                    this.init()
                    this.food.init()
                }

				break
			case 'right':
                if (this.qipan[this.h[1] + 1]) {
                    wooDir(this.qipan[this.h[0]][this.h[1] + 1], 'right')
                } else {
                    this.init()
                    this.food.init()
                }
				break
			case 'up':
				if (this.qipan[this.h[0] - 1]) {
					wooDir(this.qipan[this.h[0] - 1][this.h[1]], 'up')
				} else {
					this.init()
                    this.food.init()
				}
				
				break
			case 'down':
				if (this.qipan[this.h[0] + 1]) {
					wooDir(this.qipan[this.h[0] + 1][this.h[1]], 'down')
				} else {
					this.init()
                    this.food.init()
				}
				
				break
		}
		function wooDir(oo, dir) {
            if (oo) {
                if (oo.flag === '') {
                    oo.flag = 'snake'
                    switch (dir) {
						case 'left':
                            _this.h[1] -= 1
							break
                        case 'right':
                            _this.h[1] += 1
                            break
                        case 'up':
                            _this.h[0] -= 1
                            break
                        case 'down':
                            _this.h[0] += 1
                            break

                    }
                    _this.que.unshift(oo)
                    _this.que[_this.que.length - 1].flag = ''
                    _this.que.pop()
                } else if (oo.flag === 'snake') {
                    _this.init()
                    _this.food.init()
                } else if (oo.flag === 'food') {
                    _this.eat(oo)
                }
            } else {
                _this.init()
                _this.food.init()

            }
        }

	}
    eat (oo) {
        oo.flag = 'snake'
        this.que.unshift(oo)
        this.h = JSON.parse(JSON.stringify(oo.site))
        this.food.init()
    }

}
复制代码

最后是食物,这个就比较简单了,只要能初始化就好了。

class Food {
	constructor (qipan) {
		this.qipan = qipan
	}
	init() {
		var _this = this
		var arr = []
		_this.qipan.forEach(item=>{
			item.forEach(items=>{
				if(items.flag !== 'snake') {
					arr.push(items)
				}
			})
		})
		arr[Math.floor(Math.random()*arr.length)].flag = 'food'
	}
}
复制代码

好,三个类都准备好了,剩下的就是实例化对象,然后设置一个蛇往前走的定时器,和改变方向的监听事件,就ok了。

var qi = new Qipan(10,10, 'box')
		qi.init()
		var pan = qi.getQi()
		var time = null
		observer(pan)
		var food = new Food(pan)
        food.init()
        var sna = new Snake(pan, [0, 3],food)
        sna.init()
		var btn_s = document.getElementById('start')
		btn_s.onclick = function () {
			if (time === null) {
				time = setInterval(function(){
					sna.getGo()
				}, 200)
			}

		}
		document.onkeydown = function (ev) {
			var e = event || window.event || arguments.callee.caller.arguments[0]
			if(e && e.keyCode === 37 ){
				sna.getLeft()
            }
			if(e && e.keyCode === 38 ){
				sna.getUp()
            }
			if(e && e.keyCode === 39 ){
				sna.getRight()
            }
			if(e && e.keyCode === 40 ){
				sna.getDown()
            }
		}
复制代码

ok,这样基本的功能就实现了。完整版请看 github.com/whyjson/com… 。不过这个代码是好久之前写的了,结构很模糊,耦合性也很高,之后会优化一下代码,希望大家能够看的明白。。

盒盒盒盒。。。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Natural Language Processing with Python

Natural Language Processing with Python

Steven Bird、Ewan Klein、Edward Loper / O'Reilly Media / 2009-7-10 / USD 44.99

This book offers a highly accessible introduction to Natural Language Processing, the field that underpins a variety of language technologies, ranging from predictive text and email filtering to autom......一起来看看 《Natural Language Processing with Python》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具