美团
笔试把我乱杀
BiliBili
简历石沉大海
虾皮
笔试把我乱杀
网易
笔试把我乱杀
简答:适配器模式和装饰器模式的区别?
完美
一面
- z-index是相对于谁的z轴?
- HTTP是如何实现的
- WeakMap和WeakSet 和 Map和Set的区别
- Map和Set的作用
- apply & bind的用法
- let 暂时机制是如何实现的
- promise的catch加在then前和then后的区别
- 引用类型和基本类型的区别(存储方式)
- 线程和进程
- React diff算法
- 前端路由是如何实现的
二面
- 各种排序的时间复杂度
- 数据库中的索引是什么意思
- TCP、UDP的区别
- HTTP、HTTPS的区别
米哈游
金山云
笔试把我乱杀
京东
快手
小米
知乎
thoughtworks
SmartX
蔚来
便利蜂
陌陌
百度
一面
- dom节点转换成json数据
dom节点转成json数据
页面上存在id=jsContainer的节点A,系统会随机在节点A中生成文档片段,请按照如下需求实现 dom2json 函数
1、dom2json需要分析整个节点A的dom结构,并将其结构转换为对应的json对象
2、需要获取dom结构的标签名称(tag),所有属性(attributes),子节点(children)
3、文档片段中的属性形式均为 name="value",解析之后的格式为{name: value}, 属性值为String类型,不需要做解析
4、随机生成的文档片段中,只包含 nodeType 为1(element)和3(text)的节点,不需要考虑其他节点类型
5、纯文本也视为一个节点, json格式为 {tag: 'text', content: '文本内容'},content为文本内容执行trim后的结果,如果该结果为空,则忽略当前节点
6、返回结果中的标签名称不区分大小写
7、如果节点不包含属性值或者子节点,其对应的结果中需要保留attributes以及children字段,例如 {tag: 'div', attributes: {}, children: []}
8、当前界面执行dom2json之后的结果为如下图所示
9、请不要手动修改html和css
10、不要使用第三方插件
<div id="jsContainer">
<ul class="js-test" id="jsParent">
<li data-index="0">1</li>
<li data-index="1">2</li>
</ul>
<span style="font-weight: bold;">3</span>
4
</div>
function dom2json(id) {
let root = document.getElementById(id)
return analysisDom(root)
}
function analysisDom(d) {
let obj
//nodeType为1 => 代表element
if(d.nodeType == 1){
obj = {}
//获取d的标签名 (tagName为大写)
obj.tag = d.localName
obj.attributes ={}
let atrlen = d.attributes.length
// d.attributes为NameNodeMap类型
for(let i = 0 ; i< atrlen ; i++){
// item(x)方法用来获取第x个属性
const key = d.attributes.item(i).nodeName
const value = d.getAttribute(key)
obj.attributes[key] = value
}
obj.children = []
if(d.childNodes.length !==0){
d.childNodes.forEach(child => {
if(analysisDom(child)){
obj.children.push(analysisDom(child))
}
})
}
}//nodeType为3 => 代表text
else if(d.nodeType == 3){
let content = d.textContent.trim()
if(content){
obj = {
tag: 'text',
content,
}
}
}
return obj
}
console.log(dom2json('jsContainer'))
-
获取 url 参数
限定语言:HTML/CSS/JavaScript
获取 url 中的参数- 指定参数名称,返回该参数的值 或者 空字符串
- 不指定参数名称,返回全部的参数对象 或者 {}
- 如果存在多个同名参数,则返回数组
- 不支持URLSearchParams方法
输入: http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key
输出: [1, 2, 3]
const url = 'http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key' function get_params(url,key) { const start = url.indexOf('?') const end = url.indexOf('#') const parma_arr = url.substring(start+1,end).split('&') const map = new Map for(const param_str of parma_arr){ const params = param_str.split('=') if(map.has(params[0])){ map.set(params[0],[...map.get(params[0]),params[1]]) }else{ map.set(params[0],[params[1]]) } } console.log(map.get(key)) } get_params(url,'key')
-
防抖、节流是什么,应用场景
防抖:所有操作在一定时间间隔内都将只触发一次回调,应用:滚动,搜索栏相关词const debounce = (fn,content,delay) =>{ let movement = null return function(){ let args = arguments if(movement) { clearTimecout(movement) } movement = setTimeout(()=>{ fn.apply(content,args) },delay) } }
节流:一段时间内仅触发一次回调,应用:监听滚动条位置
const throttle = (fn,content,delay) =>{ let isAvail = true return function(){ let args = arguments if(isAvail){ isAvail = false fn.apply(content,args) setTimeout(()=>{ isAvail = true },delay) } } }
-
重绘重排何时触发?哪些变动会触发他们?
—— 概念:当DOM的变化引发了元素几何属性的变化,比如改变元素的宽高、元素的位置,导致浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为“重排”。完成重排后,要将重新构建的渲染树渲染到屏幕上,这个过程就是“重绘”。即重排负责更新元素几何属性,重绘负责更新元素样式。且重排必定重绘,但重绘不一定重排。比如改变背景色-
触发重排的操作:
- 页面渲染器初始化 (无法避免)
- 添加或删除可见DOM元素
- 元素位置改变(或使用动画)
- 元素尺寸改变
- 内容改变
- 浏览器窗口大小改变(resize事件发生时)
- 读取某些元素属性(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )当遇到 clientWidth, clientHeight, OffsetWidth, OffsetHeight 这些属性的时候,浏览器的缓存渲染队列机制将不再生效,这是因为,clientWidth 是一个元素的实时宽度,必须重排重绘以后才能得到,如果不提前进行重排重绘,clientWidth 有可能拿到的是浏览器缓存队列没执行完的时候的值。
-
触发重绘的操作:
- 改变元素外观属性。如:color,background-color等
-
-
ts装饰器的了解
装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。 Javascript里的装饰器目前处在 建议征集的第二阶段,但在TypeScript里已做为一项实验性特性予以支持。
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。 -
type和interface的区别
- type可以声明 基本类型,联合类型,元组 的别名,interface只能定义对象类型。
- type 扩展方式是 & interface是extends
- type 语句中可以使用 typeof 获取类型实例
- type 支持类型映射,interface不支持
- interface能够声明合并,type不能(interface同名合并,type同名则报错)
-
ts和js的区别
-
强缓存和协商缓存
-
React Hooks有哪些
二面
- 实现TaskManager类,使得执行run()方法后,每个task能依次执行
(依次输出 test a result a test b result b)
var taskManager = new TaskManager();
taskManager.add(function (next) {
console.log('test a')
setTimeout(function () {
console.log('result a');
next();
// ...
}, 333);
// ...
});
taskManager.add(function (next) {
console.log('test b');
setTimeout(function () {
console.log('result b');
next();
// ...
}, 22);
// ...
});
taskManager.run();
function TaskManager() {
const queue = []
TaskManager.prototype.add = function(fun) {
queue.push(fun)
}
TaskManager.prototype.run = async function(){
for(let i= 0 ; i<queue.length ; i++){
await new Promise(resolve=>{
queue[i](resolve)
})
}
}
}
- 森林的前序遍历
// type Forest = ForestNode[];
// type ForestNode = {
// v: number, // value
// c: Forest // children
// };
// For example:
var forest1 = [{v: 9}, {v: 8}, {v: 7}];
var forest2 = [
{v: 9, c: [
{v: 99},
{v: 98}
]},
{v: 8},
{v: 7}
];
var forest3 = [
{v: 9, c: [
{v: 99},
{v: 98}
]},
{v: 8},
{v: 7, c: [
{v: 79},
{v: 78, c: [
{v: 789},
{v: 788}
]},
{v: 77}
]}
];
function preOrderTraverse(forest) {
// TODO
}
console.log(preOrderTraverse(forest1)); // [9, 8, 7]
console.log(preOrderTraverse(forest2)); // [9, 99, 98, 8, 7]
console.log(preOrderTraverse(forest3)); // [9, 99, 98, 8, 7, 79, 78, 789, 788, 77]
function preOrderTraverse(forest) {
const res = []
forest.forEach(tree =>{
res.push(tree.v)
if('c' in tree){
res.push(...preOrderTraverse(tree.c))
}
})
return res
}
- js如何实现继承
三面
- 腾讯和百度都给你offer你会选择谁?
- 你对百度的认识
- 对前端前沿技术的了解
- 对前端未来趋势的看法