When the interviewer asks you a defineProperty I do not know when. . .

A front-end problem in the current environment, vue such a framework can be regarded as a basic skill, it can be said not vue difficult to find work, and most of all like to ask the interviewer is, two-way data binding on the vue principle, this problem can be said to be familiar with, that aside vue of design ideas alone is Object.defineProperty () this api, then, that you wrote this enough.

This is a very simple little game of Snake (please ignore which is very much detail bug ...), this game is achieved through defineProperty this api. The api some properties not introduced, I believe we all know.
First, the first to analyze this game, the main components are the three categories, background, food, and snakes, and the rest is the start button, no matter the time being. Then began one by one to see, start with the background, the background can be seen as similar to a checkerboard of things, since it is the board you can use it as a grid composed of plane rectangular coordinate system,

Then the mesh can be seen as a two-dimensional array, so that you can coordinate the correspondence, since use defineProperty, so every one should be a target. Well, the background of this kind of feature is probably the case.

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
	}
}
复制代码

Then we begin to hijack key corresponding to each object grid.

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'
			  			
			  		}
		        }
			})
		})
	})
}
复制代码

Parameters which describe the
configurable
if and only if the configurable attribute is true, the attribute descriptor to be able to be changed, to be deleted on the object simultaneously also from the corresponding attribute. The default is false.
enumerable
if and only if the enumerable attribute is true, the property to be able to appear in the enumeration property of the object. The default is false.
Data descriptor also has the following optional key: value
corresponding to the attribute value. JavaScript can be any valid value (numeric, objects, functions, etc.). The default is undefined.
writable
if and only if the writable attribute is true, value assignment operator can be changed. The default is false. Access descriptor also has the following optional key:
GET
a getter to provide a method attributes, if no getter was undefined. When accessing the property, which will be executed when the method is no argument to perform, but will pass this subject (due to the inheritance, this here is not necessarily define the object of the property). The default is undefined.
set
a property to provide setter method, if no setter was undefined. When the attribute value modification is triggered to perform the method. This method accepts only parameter, i.e., the properties of the new parameter value. The default is undefined.
(Excerpt from MDN)

Here we monitor the property to flag, flag indicated that the current position of the grid which is what object, if the food is in this position, then this flag is the food, when the field is changed, according to this field to determine, status of this position, and make the appropriate changes.

Let's analyze the second category, the snake, the class should have a function to initialize, move, eat food, longer, death. Here initialization and death can be seen as a way to move forward based on where we should speed up and down and around, eating food that is simple to understand and longer under a forward lattice If the food, then it becomes a direct part like a snake .

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()
    }

}
复制代码

Finally, the food, this is relatively simple, as long as the initialization enough.

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'
	}
}
复制代码

Well, three classes are ready, the rest is instantiated object, and then listen for events set a timer snake move forward, and change of direction, 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, so the basic functionality is realized. Look at the full version github.com/whyjson/com... . But long before this code is written, the structure is very vague, coupling is also high, then we will optimize the code, I hope everyone can see and understand. .
Box box box box. . .

Reproduced in: https: //juejin.im/post/5d0aed9af265da1b672113ce

Guess you like

Origin blog.csdn.net/weixin_34090562/article/details/93164373