# 写过的笔试题

# 手写bind

# bfs/dfs获取文件列表

# js获取url参数

# 深拷贝

# 编写一个 People 类

/** YIKI
 * 题目1:编写一个 People 类,使其的实例具有监听事件、触发事件、解除绑定功能。
 * (实例可能监听多个不同的事件,也可以去除监听事件)
 */
class People {
  constructor(name) {
    this.name = name
  }
  sayHi() {
    console.log(`Hi, I am ${this.name}`)
  }

  // ---------  TODO: 请在此处完善代码  -------------

  types = {}
  // key : arr
  //{ 'greeting' : [say1(),say2(),...] }

  // listenner for mutiple types
  on(eventType, ...arg) {
    let args = [...arg]
    // get its types from args and store them in types
    this.types[eventType] ?
      this.types[eventType].push(...args) :
      this.types[eventType] = args
  }

  // trigger
  emit(eventType, params) {
    let type = this.types[eventType]
    if (!type) return
    type.forEach(item => {
      item.call(this, params)
      // or item.apply(this,...params)
    })
  }


  // remove listener
  off(eventType) {
    const funcs = this.types[eventType]
    const removeType = [...arguments]
    funcs.forEach(item => {
      if (removeType.includes(item)) {
        funcs.splice(funcs.indexOf(item), 1)
      }
    })
  }
}

/* 以下为测试代码 */
const say1 = (greeting) => {
  console.log(`${greeting}, nice meeting you.`)
}
const say2 = (greeting) => {
  console.log(`${greeting}, nice meeting you, too.`)
}
const jerry = new People('Jerry')
// jerry.sayHi()// => 输出:'Hi, I am Jerry'

jerry.on('greeting', say1)
jerry.on('greeting', say2)
//jerry.on('greeting2', say1, say2)

jerry.emit('greeting', 'Hi')
//jerry.emit('greeting2', 'yiki')
// => 输出:'Hi, nice meeting you.'和 'Hi, nice meeting you, too'

jerry.off('greeting', say1)
jerry.emit('greeting', 'Hi')
//=> 只输出:'Hi, nice meeting you, too'

# 完成 sleep 函数

/**
 * 题目2:完成 sleep 函数,可以达到下面的效果:
 */
const sleep = (duration) => {
  // TODO
  let p = new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, duration)
  })
  return p
}

const anyFunc = async () => {
  console.log("123") // 输出 123
  await sleep(3000) // 暂停 300 毫秒
  console.log("456") // 输出 456,但是距离上面输出的 123 时间上相隔了 300 毫秒
}
//anyFunc()

# 完成 deepGet 函数

/**
 * 题目3:完成 deepGet 函数,给它传入一个对象和字符串,字符串表示对象深层属性的获取路径,可以深层次获取对象内容:
 */
const deepGet = (obj, prop) => {
  // TODO: 在此处完善代码
  prop.split('.').forEach(key => {
    if (key.includes('[')) {
      const index = key.match(/\[(.*)\]/)[1] // return a arr like [...]
      const prefix = key.split('[')[0] // split by [
      obj = obj[prefix][index] ? obj[prefix][index] : undefined
    } else {
      obj = obj && obj[key] ? obj[key] : undefined
    }
  })
  return obj

}

/** 以下为测试代码 */
const res1 = deepGet({
  school: {
    student: { name: 'Tomy' },
  },
}, 'school.student.name') // => 'Tomy'

const res2 = deepGet({
  school: {
    students: [
      { name: 'Tomy' },
      { name: 'Lucy' },
    ],
  }
}, 'school.students[1].name') // => 'Lucy'
// 对于不存在的属性,返回 undefined
const res3 = deepGet({ user: { name: 'Tomy' } }, 'user.age') // => undefined
const res4 = deepGet({ user: { name: 'Tomy' } }, 'school.user.age') // => undefined
// console.log(res1)
// console.log(res2)
// console.log(res3)
// console.log(res4)

# 完成 combo 函数

/**
 * 题目4:完成 combo 函数。
 * 它接受任意多个单参函数(只接受一个参数的函数)作为参数,并且返回一个函数。它的作为用:使得类似 f(g(h(a))) 
 * 这样的函数调用可以简写为 combo(f, g, h)(a)。
 */

const combo = (...func) => {
  // TODO: 请在此处完善代码
  // yiki: createCurry and start from inside 
  const funcs = [...func].reverse()
  return p => {
    funcs.reduce((prev,cur) => {
      console.log(cur(prev))
      return cur(prev)
    },p)// p is initial value
  }
}

/* 以下为测试代码 */
const addOne = (a) => a + 1
const multiTwo = (a) => a * 2
const divThree = (a) => a / 3
const toString = (a) => a + ''
const split = (a) => a.split('')

split(toString(addOne(multiTwo(divThree(666)))))
// => ["4", "4", "5"]

const testForCombo = combo(split, toString, addOne, multiTwo, divThree)
testForCombo(666)
// => ["4", "4", "5"]

# 每个人轮流从两个盘子中拿小球

/**
 * 题目5:有两个盘子分别放有 5 个和 7 个小球,两个朋友玩游戏:
 * 每个人轮流从两个盘子中拿小球,每人每次只能从其中一个盘子中拿,每次可以拿 1 个或者多个(不能一个都不拿),
 * 拿到最后一个小球的人算输。问开局先手和后手是否有必胜策略?如果有,请描述必胜策略。
 * 
 * yiki:
 * 先手必胜 
 * 先手每一次操作都令两个盘子的球数相等直到决胜轮,先手在首次令盘子里数量相等的情况下后手没有必胜策略
 * 一些个人见解,不一定正确:
 * 二进制异或 5 = 0101 
 *          7 = 0111 
 *    5 xor 7 = 0010 = 1 先手输
 * 要令异或为0 则 5 xor 5 = 0 先手才能赢 则 先手令 7 - 2 = 5 ( 2 = 0010)
 * 之后每一步当后手破坏xor为0时 先手重新令xor的结果为0即可
 */
Last Updated: 2022/6/26 上午11:43:14