今年和以往一个区别就是有一些大厂增加了手写前端逻辑 或者 收集算法这个环节。前端的一些语言特性,异步控制相对好准备,大多都是Promise的使用外加递归。算法就相对来说难准备一些。需要一个长时间的积累。本文分几类来举例。抛转引玉。
这部分主要考察对于js语言本身的理解,如this,原型链的理解,instanceOf,new关键字等。
Function.prototype.mybind = function(context, ...args) { let fun = this; function bound(...args2) { let self = this instanceof bound ? this : context; return fun.apply(self, args.concat(args2)); } bound.prototype = Object.create(fun.prototype); return bound; }; 复制代码
function isInstanceOf(child, fun) { if (typeof fun !== "function") { throw new TypeError("arg2 fun is not a function"); } if (child === null) { return false; } if (child.__proto__ !== fun.prototype) { return isInstanceOf(child.__proto__, fun); } return true; } 复制代码
function myNew(fun, ...arg) { if (typeof fun !== "function") { throw new TypeError(" fun is not a function"); } let obj = {}; Object.setPrototypeOf(obj, fun.prototype); fun.apply(obj, arg); return obj; } 复制代码
function JSONParse(strs) { if (strs === "" || typeof strs !== "string") { throw new SyntaxError("JSONParse error"); } if (strs[0] === "{") { let obj = {}; if (strs[strs.length - 1] == "}") { let fields = strs.substring(1, strs.length - 1).split(","); for (let field of fields) { let index = field.indexOf(":"); let temp = []; if (index !== -1) { temp[0] = field.substring(0, index); temp[1] = field.substring(index + 1, field.length); } let key = temp[0].substring(1, temp[0].length - 1); let value = parseValue(temp[1]); //if (value !== undefined) { obj[key] = value; //} } } console.log("prase:", obj); return obj; } if (strs[0] === "[") { if (strs[strs.length - 1] == "]") { let result = []; let fields = strs.substring(1, strs.length - 1).split(","); for (let field of fields) { result.push(parseValue(field)); } return result; } } } 复制代码
function JSONStringify(obj) { if ( obj === undefined || obj === null || typeof obj === "string" || typeof obj === "boolean" || typeof obj === "number" ) { return obj; } if (typeof obj === "function") { return ""; } if (Array.isArray(obj)) { let result = []; for (let i = 0; i < obj.length; i++) { result.push(JSONStringify(obj[i])); } return "[" + result.join(",") + "]"; } else { let result = []; for (let key in obj) { result.push(`"${key}":${JSONStringify(obj[key])}`); } return "{" + result.join(",") + "}"; } } 复制代码
function myExtends(parent, child) { function nop() {} nop.prototype = parent.prototype; child.prototype = new nop(); } 复制代码
这部分都是前端的一些高阶函数(闭包)。通常用来解决一些通用的问题。这个思想和J2EE中的(面向切面编程)AOP非常相似。例如debounce,memorize
debounce(fun, delay, immediate) { let timer = null; return (...args) => { if (timer) { clearTimeout(timer); } else { timer = setTimeout(() => { fun.apply(this, args); }, delay); } }; } 复制代码
throttle(fun, delay, immediate) { let flag = false; return (...args) => { if (!flag) { flag = true; setTimeout(() => { fun.apply(this, args); flag = false; }, delay); } }; }, 复制代码
memeorize(fun) { let cache = {}; return (...args) => { const key = args.toString(); if (cache[key]) { return cache[key]; } let value = fun.apply(this, args); cache[key] = value; return value; }; } 复制代码
promisy(fun) { return (...args) => { return new Promise((resolve, reject) => { try { fun(...args, resolve); } catch (e) { reject(e); } }); }; } //使用方法 fun(arg1,callback); let promisey = promisy(fun); promisey().then((res)=>()); 复制代码
currying(fun) { function helper(fn, ...arg1) { let length = fn.length; let self = this; return function(...arg2) { let arg = arg1.concat(arg2); if (arg.length < length) { return helper.call(self, fn, ...arg); } return fn.apply(this, arg); }; } return helper(fun); } //例子 function add(a, b) { return a + b; } let curryadd = util.currying(add); let add1 = curryadd(1); t.is(add1(2), 3); 复制代码
formatNumber(number) { if (typeof number !== "number") { return null; } if (isNaN(number)) { return null; } let result = []; let tmp = number + ""; let num = number; let suffix = ""; if (tmp.indexOf(".") !== -1) { suffix = tmp.substring(tmp.indexOf(".") + 1); num = parseInt(tmp.substring(0, tmp.indexOf("."))); } while (num > 0) { result.unshift(num % 1000); num = Math.floor(num / 1000); } let ret = result.join(","); if (suffix !== "") { ret += "." + suffix; } return ret; } 复制代码
这类问题大多是递归外加promise的理解。大家可以着重看看promise的使用。掌握了promise还是很好解决这些问题的。 -实现一个sleep的函数。sleep(3000).then(()=>{})
function sleep(delay){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve() },delay); }) } 复制代码
-使用XMLHttpRequest 实现一个Promise的ajax
function myRequest(url, method, params) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.onreadystatechange = () => { if (xhr.readyState != 4) { return; } if (xhr.state === 200) { resolve(xhr.response); } }; xhr.addEventListener("error", e => { reject(error); }); xhr.send(params); }); } 复制代码
-用promise 实现一个lazyman. LazyManAsync("Hank").sleepFirst(5).eat("supper"); LazyManAsync("Hank").sleep(10).eat("dinner")
export function LazyManAsync(name) { return new LazyManFactory(name); } function LazyManFactory(name) { this.tasks = []; this.tasks.push(() => { return new Promise((resolve, reject) => { console.log("hi", name); resolve(); }) }); setTimeout(() => { this.run(); }, 0); } LazyManFactory.prototype.run = function () { if (this.tasks.length === 0) { return; } let task = this.tasks.shift(); task().then(() => { this.run(); }).catch(() => { this.run(); }) } LazyManFactory.prototype.sleep = function (time) { this.tasks.push(() => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, time * 1000) }) }) return this; } LazyManFactory.prototype.eat = function (name) { this.tasks.push(() => { return new Promise((resolve, reject) => { console.log("eat:", name); resolve(); }) }) return this; } LazyManFactory.prototype.sleepFirst = function (time) { this.tasks.unshift(() => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, time * 1000) }) }) return this; } 复制代码
这类一般涉及到算法。这部分短时间不好准备,建议可以作为长期战略来复习。这里暂时只列出非常高频的简单题。实际面试中有可能难度大大超过下面。
const twoSum = function(arys, target) { if (!Array.isArray(arys)) { throw new TypeError("arg1 is not a array"); } const map = new Map(); for (let i = 0; i < arys.length; i++) { let num = target - arys[i]; if (map.get(num) !== undefined) { return [map.get(num), i]; } map.set(arys[i], i); } return []; }; 复制代码
const quickSort = function(ary = [], start = 0, end = ary.length - 1) { if (!Array.isArray(ary)) { throw new TypeError("arg1 is not a array"); } if (start >= end || isNaN(start) || isNaN(end)) { return; } let index = partition(start, end); quickSort(ary, start, index - 1); quickSort(ary, index + 1, end); function partition(left, right) { let priviot = ary[right]; let k = left - 1; for (let i = left; i <= right - 1; i++) { if (ary[i] <= priviot) { swap(++k, i); } } swap(++k, right); return k; } function swap(i, j) { let temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; } }; 复制代码
const binarySearch = function(ary, target) { if (!Array.isArray(ary)) { throw new TypeError("arg1 is not a array"); } let start = 0, end = ary.length - 1; while (start <= end) { let mid = Math.floor(start + (end - start) / 2); if (ary[mid] === target) { return mid; } else if (ary[mid] < target) { start = mid + 1; } else { end = mid - 1; } } return -1; }; 复制代码
const flush = function(num = []) { for (let i = 0; i < num.length; i++) { let index = Math.floor(Math.random() * (num.length - 1)); let temp = num[i]; num[i] = num[index]; num[index] = temp; } }; 复制代码
const f = (n)=>{ if(n<0){ return 0; } if(n === 0 ){ return 1; } return f(n-1)+f(n-2); } 复制代码
var subsets = function(nums) { let result = []; function dfs(index,ans){ let ans2 = ans.concat(); ans2.push(nums[index]); if(index === 0){ result.push(ans); result.push(ans2); return; }else{ dfs(index-1,ans); dfs(index-1,ans2); } } dfs(nums.length-1,[]); return result; }; 复制代码
文中出现的题目,本人在github上总结了一个项目 turtle-rock .如果您觉得帮助了到你,请帮忙给个star。你的star,是我写作的动力。