有赞面试记录一 - pod4g/tool GitHub Wiki
这是有赞的第二面(第一面主要问了很多项目问题,不方便写出来),全部是coding题,在40分钟之内全部做了出来,做个记录
// =====================================================
// 欢迎参加有赞前端 Coding 面试
// =====================================================
// 界面介绍:
// 上方设置按钮可以切换语言、字体大小、主题
// 右侧控制台可以显示代码执行结果,可用于编码过程中的 DEBUG
// =====================================================
// Coding 须知:
// 本次 Coding 时间限制为 45 分钟,共 3 道题目
// 题目难度自上向下递增,请量力答题
// =====================================================
/**
* 解析url中的queryString
*
* 输入:https://www.youzan.com?name=coder&age=20&callback=https%3A%2F%2Fyouzan.com%3Fname%3Dtest&list[]=a&json=%7B%22str%22%3A%22abc%22,%22num%22%3A123%7D
* 输出:
* {
* name: coder,
* age: 20,
* callback: https%3A%2F%2Fyouzan.com%3Fname%3Dtest,
* list: [a],
* json: {
* str: 'abc',
* num: 123
* }
* }
*/
function safyParse(json) {
let obj = null
try {
obj = JSON.parse(json)
} catch(e) {}
return obj
}
const url = 'https://www.youzan.com?name=coder&age=20&callback=https%3A%2F%2Fyouzan.com%3Fname%3Dtest&list[]=a&json=%7B%22str%22%3A%22abc%22,%22num%22%3A123%7D';
function parseQuery(url) {
url = url.toString()
if (typeof url !== 'string') { throw new TypeError('arguments should be a string type') }
const [ host, queryString ] = url.split('?')
const querys = queryString.split('&')
const map = Object.create(null)
const arrayReg = /\[\]$/
for(let query of querys) {
let [k, v] = query.split('=')
if (arrayReg.test(k)) {
const list = []
list.push(k)
k = k.replace(arrayReg, '')
v = list
} else if (/^\{\[/.test(decodeURIComponent(v))) {
v = safyParse(v)
}
map[k] = v
}
return map
}
console.log(parseQuery(url));
/**
* 统计一个复杂对象中的英文字符 a-z以及A-Z个数,
* 输入:
* {
* name: 'code',
* obj: {
* name: 'CODE',
* age: [12, 45, 20],
* info: {
* nick: 'haha!'
* }
* },
* hooby: ['a', 'B']
* }
* 输出:14
*/
const obj = {
name: 'code',
obj: {
name: 'CODE',
age: [12, 45, 20],
info: {
nick: 'haha!'
}
},
hooby: ['a', 'B']
}
function getType(arg) {
return Object.prototype.toString.call(arg).slice(8, -1).toLowerCase()
}
console.log(getType('abc'))
function calcCountOfObject(obj) {
if (obj == null && getType(obj) !== 'object') {
throw new TypeError('argument should be a object type')
}
let counter = 0
const reg = /[a-zA-Z]/
Object.keys(obj).forEach(key => {
const value = obj[key]
const type = getType(value)
if (type === 'string') {
for (let i = 0; i < value.length; i++) {
if(reg.test(value[i])) {
counter++
}
}
} else if (type === 'object' || type === 'array') {
counter += calcCountOfObject(value)
}
})
return counter
}
console.log(calcCountOfObject(obj));
/**
* 3. 请实现一个事件模型(EventEmitter)
* 实现简单的 on、off、once等功能
*/
class EventEmitter {
constructor() {
// 数据结构
// { eventName1: { queue: [fn1, fn2, fnn], called: false }, eventName2: }
this.map = {}
}
__inqueue(eventName) {
const { queue } = this.map[eventName]
if (queue && queue.length > 0) {
if (queue.inclues(callback)) {
queue.push(callback)
}
} else {
// 如果没有,则实例化一个队列
map[eventName] = [callback]
}
}
on(eventName, callback) {
this.__inqueue(eventName)
}
off(eventName) {
// 简单粗暴,直接清空回调队列
map[eventName] = []
}
once(eventName, callback) {
const { called } = map[eventName]
if (called) { return }
this.__inqueue()
}
}