700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 当面试官问你了不了解defineProperty的时候。。。

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

时间:2020-04-28 16:00:22

相关推荐

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

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

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

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

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

class Qipan {constructor(w, h, id){this.w = wthis.h = hthis.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 = temthis.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 = qipanthis.h = hthis.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 = thisswitch (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()}breakcase '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()}breakcase '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()}breakcase '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] -= 1breakcase 'right':_this.h[1] += 1breakcase 'up':_this.h[0] -= 1breakcase 'down':_this.h[0] += 1break}_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 = thisvar 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 = nullobserver(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,这样基本的功能就实现了。完整版请看 /whyjson/com… 。不过这个代码是好久之前写的了,结构很模糊,耦合性也很高,之后会优化一下代码,希望大家能够看的明白。。

盒盒盒盒。。。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。