字节tiktok前端面经
反正不会去了
一面
判断链表是否有环
function ListNode(val) { this.val = val; this.next = null; } function isCircle(head) { if (!head || !head.next || (!(head instanceof ListNode))) return false; let fast = head; let slow = head; while(fast && fast.next) { slow = slow.next; fast = fast.next.next; if (slow === fast) return true; } return false; } let p0 = new ListNode(0); let p1 = new ListNode(1); let p2 = new ListNode(2); p0.next = p1; p1.next = p2; p2.next = p1; console.log(isCircle(p0));
异步加法
// 假设有一台本地机器,无法做加减乘除运算(包括位运算)。 // 因此无法执行 a + b、a+ = 1 这样的 JS 代码。 // 然后我们提供一个服务器端的 HTTP API。 // 可以传两个数字类型的参数,响应结果是这两个参数的和。 // 这个 HTTP API 的 JS SDK(在本地机器上运行)的使用方法如下: // SDK 的模拟实现: function asyncAdd(a, b, cb) { setTimeout(() => { cb(null, a + b); }, Math.floor(Math.random()*1000)) } // SDK 模拟调用 asyncAdd(3, 5, (err, result) => { console.log(result); // 8 }); async function sum(...args) { if (args.length < 2) return args[0] || 0; if (args.length === 2) return await asyncAdd(args[0], args[1]); const len = args.length; const half = (len >> 1); const left = await sum(...args.slice(0, half + 1)); const right = await sum(...args.slice(half + 1)); res = asyncAdd(left, right); // let res = args[0]; // for (let i = 1; i < args.length; i++) { // res = await asyncAdd(sum, args[i]); // } return res; } // 现在要求在本地机器上实现一个 sum 函数,支持以下用法: (async () => { const result1 = await sum(1, 4, 6, 9, 2, 4); const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7); const result3 = await sum(1, 6, 0, 5); console.log([result1, result2, result3]); // [26, 36, 12] })();
完整解法
function asyncAdd(a, b, cb) { setTimeout(() => { cb(null, a + b); }, Math.floor(Math.random()*100)) } function sum(...args) { const result = [] function _sum(resolve, reject) { new Promise((r, j) => { let a = args.pop() let b = args.pop() a = a !== undefined? a : 0 b = b !== undefined? b : 0 // 如果访问的元素超出了数组范围,则转为 0 asyncAdd(a, b, (err, res) => { if (err) j(err) r(res) }) if (args.length) { _sum(resolve, reject) } }) .then(val => { result.push(val) setTimeout(() => { if (args.length <= 0) { resolve(sum(...result)) } }, 100) }) } return new Promise((resolve, reject) => { if (!args || !args.length) resolve(0) if (args.length == 1) resolve(args[0]) _sum(resolve, reject) }) } (async () => { const result1 = await sum(1, 4, 6, 9, 1, 4) const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7) const result3 = await sum(1, 6, 0, 5) console.log([result1, result2, result3]) // [25, 36, 12] })()
二面
以下的结果?
[] == ![]
浏览器的渲染机制
repaint 和 reflow
const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2); }) promise.then(() => { console.log(3); }) console.log(4);
class promise { constructor() { this.status = 'pending'; } then(onResvoled, onRejected) { } }
用 React 实现一个树型结构
{ list: [{ id: '1', name: 'folder1', children: [{ id: '11', name: 'file1' }, { id: '12', name: 'file2' }] }, { id: '2', name: 'folder2', children: [{ id: '21', name: 'folder3', children: [{ id: '211', name: 'file3' }] }] }, { id: '3', name: "file4" }] }
我当场写的
function TreeView(props) { conste {data, level = 0} = props; return (data.map(item => { const level = item.id.length; return ( <div> <span> {'-'.repeat(level)} </span> <span> {item.name} </span> {item.children && item.children ? <TreeView data={item.child} level={level + 1}></TreeView> : ''} </div> ) })) }
如果让你来设计一个分页功能,你会怎么设计?前后端如何交互?
HTTP 缓存
TCP/UDP
三面
项目经历
第一道题给我pass了,看我原生js不太行了
实现一个组件,包括 HTML/CSS/JS,点击后出现弹框,需求写弹框,要求可以这么使用,样式尽量的还原设计稿:
function confirm(title, desc) { // TODO } const yes_no = await confirm( 'Do you Want to delete these items', 'Some descriptions'); if(yes_no) { // the user confirmed. }
第2题
给定一个由'1'(陆地)和'0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
[
[1,1,1,1,0],
[1,1,0,1,0],
[1,1,0,0,0],
[0,0,0,0,0],
]
输出: 1
示例 2:
输入:
[
[1,1,0,0,0],
[1,1,0,0,0],
[0,0,1,0,0],
[0,0,0,1,1],
]
输出: 3
我用的BFS
function findNumOfIsland(arr) { const m = arr.length; if (!m) return 0; const n = arr[0].length; if (!n) return 0; let res = 0; for (let i = 0; i < m; i++) { for (let j = 0; j < n; j++) { if (arr[i][j] === 0) continue; res++; const queue = [[i, j]]; arr[i][j] = 0; while (queue.length) { const [x, y] = queue.shift(); if (x >= 1 && arr[x - 1][y] === 1) { queue.push([x - 1, y]); arr[x - 1][y] = 0; } if (y >= 1 && arr[x][y - 1] === 1) { queue.push([x, y - 1]); arr[x][y - 1] = 0; } if (x < m - 1 && arr[x + 1][y] === 1) { queue.push([x + 1, y]); arr[x + 1][y] = 0; } if (y < n - 1 && arr[x][y + 1] === 1) { queue.push([x, y + 1]); arr[x][y + 1] = 0; } } } } return res; } arr = [ [1,1,0,0,0], [1,1,0,0,0], [0,0,1,0,0], [0,0,0,1,1], ] console.log(findNumOfIsland(arr));
第3题
任务
面试官提出的问题将出现在这里。
URL参数解析:
http://www.tiktok.com/a/b?key=1&key=2&key=3&test=4#hehe
{
host: 'www.tiktok.com',
protocol: 'http',
path: '/a/b',
query: {
key: [],
test: '4'
},
hashtag: 'hehe'
}
忘了考虑一些边界情况,面试官也没让我写了
function decode(url) { let arr = url.split("://"); const protocol = arr[0]; url = arr[1] || ''; arr = url.split('/'); const host = arr.shift(); url = arr.join('/'); arr = url.split('?'); const path = arr.length === 2 ? '/' + arr.shift() : ''; url = arr[0]; arr = url.split('#'); const hash = arr.length === 2 ? arr[1] : ''; const query = {}; arr = arr[0].split('&'); for (let i = 0; i < arr.length; i++) { const [key, value] = arr[i].split('='); if (query[key]) { if (Array.isArray(query[key])) { query[key].push(value); } else { query[key] = [ query[key], value ] } } else { query[key] = value; } } return { host, protocol, path, query, hash } } const url = 'http://www.tiktok.com/a/b?key=1&key=2&key=3&test=4#hehe' console.log(JSON.stringify(decode(url)));#字节跳动##笔经#