19秋招面经
8.11 & 8.12笔试
顺丰科技二面 8.11(视频)
- 自我介绍 + 实习经历介绍
- 未来职业规划
- 为什么想来顺丰
- 了解过顺丰科技的业务吗?为什么没关注?
- 学习工作中遇到过什么比较困难的事情?怎么解决?
- 期望薪资?能降吗?
- 提问
猿辅导现场二面 8.10
- 自我介绍 + 实习经历
- 算法题1:使用setTimeout实现setInterval功能
function mySetInterval(fn, ms) {
function interval(){
setTimeout(interval, ms);
fn();
}
setTimeout(interval, ms);
}
// 更好的实现
function mySetInterval(fn, ms, count) {
function interval() {
if(typeof count === 'undefined' || count-- > 0) {
setTimeout(interval, ms);
try {
fn();
} catch(e) {
t = 0;
throw e.toString();
}
}
}
setTimeout(interval, ms);
}
- 算法题2:使用递归和非递归两种方法统计一棵二叉树的深度
- 算法题3:在一个无序数组中,寻找连续两个及两个以上的相同元素的个数
例如:有数组[10, 22, 32, 4, 4, 5, 6, 9, 8, 8, 2],返回结果为2
4, 4
8, 8
- 算法题3延伸:如果给定的是一个有序数组,如何优化?
猿辅导现场一面 8.10
- 自我介绍 + 实习经历
- 为什么会选前端
- React:生命周期 + 组件间数据传递 + ref
- 原生JS:作用域链 + 原型链 + 闭包
- 缓存机制(强缓存 + 协商缓存) + 相关HTTP头部信息
- URL从输入网址到最终呈现的流程 + 哪些步骤可以优化
- Canvas API
- 算法题:判断一棵二叉树是对称的
CVTE终面(视频) 8.10
太多了,跟面试前补充的简历几乎一样
顺丰科技一面 8.4 (视频)
- 自我介绍 + 项目 + 实习
- 研究生之后记忆深刻的事
- 原型的理解
- 闭包的理解
- ES5/ES6创建对象的方法
- ES5/ES6继承的方法
- 前端语言体系三要素
- HTML语义化
根据内容的结构化(内容语义化),选择合适的标签(代码语义化),
便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析
- React的Virtual Dom/Diff算法
- Set和Map区别
- HTTP与TCP/IP或Socket的区别
TCP连接 需要经过“三次握手”
HTTP/1.0 客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接
HTTP/1.1 一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求
- 为什么投顺丰科技
- 提问
补充:
- 前端兼容性问题
- Webpack更新原理
- CSS Hack
- 箭头函数为什么不能作为构造函数
- npm发布版本号
- package.json和package-lock.json区别
- CSS菊花图(animation-delay实现)
- Object.create实现
大疆二面 8.2(视频)
- 自我介绍
- 工作过程中遇到什么困难?
- 怎么跟产品经理沟通的?出现问题的原因在哪里?如何解决?最终达成一致的立足点是什么?
- 如何学习的?写过组件库吗?看过或自己有开源项目吗?
- 了解React Native吗
- 了解C/C++吗?(懂Java)那说说Java内存机制?
- 数据结构了解?哪些排序算法?实际中有用吗?
- 你希望的工作环境是怎样的?
- 你对996制度怎么看?
- 你有什么问题?
CVTE二面 8.1(视频)
- 自我介绍
- 前端的学习曲线
- 对自己未来的规划
- React的diff算法
- React生命周期,setState能用在componentWillUpdate里吗?
- 算法题:字符串最长不重复子串的长度
- 最近看什么新知识
CVTE一面 7.29
- 最近做什么项目?
- 跨域了解过哪些?跨域传cookie可以使用哪种方法?
第一步:
设置响应消息头Access-Control-Allow-Credentials值为“true”。
同时,还需要设置响应消息头Access-Control-Allow-Origin值为指定单一域名
第二步:
客户端需要设置Ajax请求属性withCredentials=true,让Ajax请求都带上Cookie
- 怎么处理cookie?删除cookie?
- insertBefore方法
- JS异步解决方案
- 浏览器端的EventLoop和Node的EventLoop
- setTimeout和Ajax的优先级
- JS实现事件绑定的方法
1. elementObject.addEventListener(eventName,handle,useCapture)
2. elementObject.attachEvent(eventName,handle);(仅支持IE8及以下)
3. document.getElementById("demo").onclick = function(){};
- CSS如何适配浏览器大小?
1. <meta name="viewport"
content="width=device-width,
height=device-height,
inital-scale=1.0,
maximum-scale=1.0,
user-scalable=no;"
/>
2. 网页内部的元素宽度要使用百分比,在不同的屏幕大小下需使用媒体查询定义不同的css代码
代码解析:
width:控制 viewport 的大小,可以是指定的一个值,比如 1920,或者是特殊的值,如 device-width 为设备的宽度,单位为缩放为 100% 时的 CSS 的像素。
height:和 width 相对应,指定高度,可以是指定的一个值,比如 1080,或者是特殊的值,如 device-height 为设备的高度。
initial-scale:初始缩放比例,即当页面第一次载入是时缩放比例。
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放。
- 浏览器的内核有哪些?哪些CSS属性需要设置?
1. IE: Trident内核
2. Firefox:Gecko内核
3. Google:Blink内核
4. Safari:Webkit内核
-webkit- ,针对safari,chrome浏览器的内核CSS写法
-moz-,针对firefox浏览器的内核CSS写法
-ms-,针对ie内核的CSS写法
-o-,针对Opera内核的CSS写法
- 三列布局的实现
- 三角形的实现
- HTTP/1.1和HTTP/1.0的区别
- HTTP的状态码
- 浏览器缓存的分类
- cache-control的值有哪些?
- 对JS原型链的理解
- 实现方法?弊端?
- 平常怎么学前端?
- 为什么选择前端?
- 有写博客吗?有给开源项目贡献代码吗?
阿里飞猪二面 7.25
- 自我介绍 + 实习情况
- 如何判断Array
- React-router原理?用到哪些API?
- React实现幻灯片组件对外暴露的接口有哪些?
- CSS第三方库的原理
- CSS响应式设计的方式
CSS响应式设计适配多种设备:
1. <meta name="viewport" content="width=device-width, initial-scale=1" />
2. 不要使用绝对宽度
3. 字体大小和长宽边距属性不要用”px”,应该用相对大小的“rem”
4. 使用流动布局
- 如果宽度太小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现
5. link标签的media属性
- <link rel="stylesheet" type="text/css" media="screen and (min-width: 600px) and (max-device-width: 980px)"
href="css600-980.css" />
6. Media Query
7. 图片的自适应(自动缩放)
- img{max-width: 100%;}
- 最好还是根据不同大小的屏幕,加载不同分辨率的图片
- XSS和CORS原理及解决方案
- HTTP和HTTPS的区别
- 前端优化的方法
- utf-8和unicode区别
1. Unicode是'字符集',utf-8是'编码规则'
(以8位为一个编码单位的可变长编码,会将一个码位编码为1到4个字节)
2. 字符集:为每一个字符分配一个唯一的ID
编码规则:将码位转为字节序序列的规则
例如:'知'的码位是30693,记作U+7735(16进制为0x77E5)
'Unicode与utf-8关系':
U+0000 - U+007F:0XXXXXXX
U+0080 - U+07FF:110XXXXX 10XXXXXX
U+0800 - U+FFFF:1110XXXX 10XXXXXX 10XXXXXX
U+10000 - U+1FFFF:11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
3. utf-16使用2或4字节来保存,utf-32使用4字节保存
'GBK与utf-8':
- UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。
- GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。
- GBK的文字编码是用'双字节'来表示的,为了区分中文,将其最高位都设定成1,通用性比UTF8差。
大疆一面 7.24
- 自我介绍
- React-router原理 + SPA
- React-router的Link和a标签的跳转有什么区别?
- Link按需更新,a标签会重复渲染、造成白屏
补充: React-router中的Link和Route的区别
- route是配置,link是使用
- 静态跳转:通过Link组件实现静态跳转
- 必须以写入组件的方式实现跳转
- 无法跳到历史记录中的前一个界面,后一个界面,前N个界面,后N个界面
- 动态跳转:通过Route注入component中的route属性实现动态跳转
- 从Route组件中传入component中的router属性对象解决了这个问题
- NavLink是Link的一个特定版本,会在匹配上当前的url的时候给已经渲染的元素添加参数
- state和props的区别
- virtual DOM和diff算法
- Ajax请求应该在哪个生命周期函数中?为什么不在componentWillMount里?
- 在componentDidMount中
- ajax请求在返回数据后需调用setState方法,进而更新state值,但componentWillMount并不允许(该函数效果与constructor相同,只能设定state初始值),无法触发重渲染
- key有什么作用?为什么不应该用数组的index值当key?(不稳定)
- 算法题:在局部递增数组(如:[3, 4, 5, 1, 2])中查询指定数字是否存在
- React学了多久?
- 提问
拼多多笔试 7.22
- 下面的输出是什么?
const promise = new Promise((resolve, reject) => {
console.log('a');
resolve();
console.log('b');
});
promise.then(() => {
console.log('c');
});
console.log('d');
// a b d c,Promise的异步执行
- 下面的输出是什么?
(function(x) {
return (function(y) {
console.log(x);
})(2);
})(1);
// 1,闭包问题
- 下面的输出是什么?
pi = 0;
radius = 1;
function circum(radius) {
radius = 3;
pi = 3.14;
console.log(2 * pi * radius); // 18.14
console.log(arguments[0]); // 3
}
circum(2);
console.log(pi); // 3.14
console.log(radius); // 1
函数内修改了radius 修改的是"形式参数",修改的pi是"全局的"pi
与下述情况相同
var pi = 0;
var radius = 1;
function circum(radius) {
radius = 3;
pi = 3.14;
console.log(2 * pi * radius); // 18.84
console.log(arguments[0]); // 3
}
circum(radius);
console.log(pi); // 3.14
console.log(radius); // 1
补充
function foo(a, b){
arguments[0] = 9;
arguments[1] = 99;
console.log(a, b); //9, 99
}
foo(1, 10);
function foo(a, b){
a = 8;
b = 88;
console.log(arguments[0], arguments[1]); //8, 88
}
foo(1, 10);
// ES6的默认函数不会改变arguments类数组对象值
function foo(a=1, b=10){
arguments[0] = 9;
arguments[1] = 99;
console.log(a, b); //1, 10
}
foo();
// 实例
function f2(a) {
console.log(a);
var a;
console.log(a);
console.log(arguments[0])
}
f2(10)
经过变量提升后:
function f2(a) {
var a;
console.log(a);
console.log(a);
console.log(arguments[0])
}
f2(10);
var a会被归纳,由于a已经有值,故不会变为undefined
- 哪些是稳定排序?哪些是不稳定排序? 定义: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
稳定排序:
插入排序 [1] ,冒泡排序 [2] ,归并排序 [3] ,基数排序 [4] ,计数排序 [5]
不稳定排序:
快速排序 [1],简单选择排序 [2],希尔排序 [3],堆排序 [4]
- typeof obj === 'object'判断obj是对象的弊端?如何改进?
var obj = {};
var arr = [];
var funcInstance = new (function (){});
var isNull = null;
console.log(typeof obj === 'object'); //true
console.log(typeof arr === 'object'); //true
console.log(typeof funcInstance == 'object'); //true
console.log(typeof isNull === 'object'); // true
// constructor
({}).constructor === Object; //true
([]).constructor === Array; //true
// instanceof
({}) instanceof Object; //true
([]) instanceof Array; //true
// toString: 将当前对象以字符串的形式返回
console.log(Object.prototype.toString.call(obj)); //[object Object]
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(null)); //[object Null]
- 补充题:下面的输出是什么?
var a = {};
var b = {name:"ZS"};
var c = {};
c[a] = "demo1";
c[b] = "demo2";
console.log(c[a]); // demo2
console.log(c); // Object {[object Object]: "demo2"}
c[a]、c[b]隐式的将对象a,b使用了toString()方法进行了转换,然后再对属性赋值。
即:Object.prototype.toString.call(a) ==> [object Object]
因此,c = { [object Object]: 'demo1'} ==> c = {[object Object]: 'demo2' }
- 编程:实现log函数
function log() {
// var arr = [].slice.call(arguments);
var arr = Array.from(arguments);
var res = '';
arr.forEach(elem => {
res += elem + ' ';
});
console.log(`(app)${res}`);
}
// 测试
log('hello', 'world');
log('hello world');
- 将具有父子关系的原始数据格式化成树形结构数据 第一种思路:
function toTreeData(data){
var pos={};
var tree=[];
var i=0;
while(data.length!=0){
if(data[i].pid==0){
tree.push({
id:data[i].id,
text:data[i].text,
children:[]
});
pos[data[i].id]=[tree.length-1];
data.splice(i,1);
i--;
}else{
var posArr=pos[data[i].pid];
if(posArr!=undefined){
var obj=tree[posArr[0]];
for(var j=1;j<posArr.length;j++){
obj=obj.children[posArr[j]];
}
obj.children.push({
id:data[i].id,
text:data[i].text,
children:[]
});
pos[data[i].id]=posArr.concat([obj.children.length-1]);
data.splice(i,1);
i--;
}
}
i++;
if(i>data.length-1){
i=0;
}
}
return tree;
}
var data=[
{id:1,pid:0,text:'A'},
{id:2,pid:4,text:"E[父C]"},
{id:3,pid:7,text:"G[父F]"},
{id:4,pid:1,text:"C[父A]"},
{id:5,pid:6,text:"D[父B]"},
{id:6,pid:0,text:'B'},
{id:7,pid:4,text:"F[父C]"}
];
var result = toTreeData(data);
console.log(result);
第二种思路:
function treeObj(originObj) {
// 深拷贝
let obj = {};
for(key in originObj) {
var val = originObj[key];
// arguments的callee属性指向拥有这个 arguments 对象的函数
obj[key] = typeof val === 'object'? arguments.callee(val):val;
}
obj['children'] = [];
return obj;
}
function toTreeData(data, attributes) {
let resData = data;
let tree = [];
// 找根节点
for(let i = 0; i < resData.length; i++) {
if(resData[i][attributes.parentId] === ''
||
resData[i][attributes.parentId] === null) {
tree.push(treeObj(resData[i]));
// 删除掉已经放入tree中的根节点
resData.splice(i, 1);
i--;
}
}
// 找寻子树
return run(tree);
function run(childArr) {
if(resData.length !== 0) {
for(let i = 0; i < childArr.length; i++) {
for(let j = 0; j < resData.length; j++) {
if(childArr[i][attributes.id] === resData[j][attributes.parentId]) {
let obj = treeObj(resData[j]);
childArr[i].children.push(obj);
// 删除加入树中的节点
resData.splice(j, 1);
j--;
}
}
run(childArr[i].children);
}
}
return tree;
}
}
let allRes = [
{
id: 4,
resName: "删除角色",
parentId: 2
},
{
id: 3,
resName: "编辑角色",
parentId: ''
},
{
id: 2,
resName: "设置权限",
parentId: ''
},
{
id: 5,
resName: "添加用户",
parentId: 4
},
{
id: 6,
resName: "更新用户",
parentId: 4
},
{
id: 7,
resName: "删除用户",
parentId: 6
},
{
id: 8,
resName: "重置密码",
parentId: 3
},
{
id: 9,
resName: "添加地区",
parentId: 5
},
{
id: 10,
resName: "编辑地区",
parentId: 6
}
];
let data = allRes;
// 属性配置信息
let attributes = {
id: 'id',
parentId: 'parentId',
};
let treeData = toTreeData(data, attributes);
console.log(treeData);
- 深拷贝与浅拷贝的区别?如何实现?
- 浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存
- 深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变
// 1. Object.assign
let foo = {
a: 1,
b: 2,
c: {
d: 1,
}
}
let bar = {};
Object.assign(bar, foo);
foo.a++;
foo.a === 2 //true
bar.a === 1 //true
foo.c.d++;
foo.c.d === 2 //true
bar.c.d === 1 //false
bar.c.d === 2 //true
Object.assign()是一种可以对非嵌套对象进行深拷贝的方法;
如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝。
// 2. JSON.parse和JSON.stringify
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1); // { body: { a: 10 } }
console.log(obj2); // { body: { a: 20 } }
console.log(obj1 === obj2); // false
console.log(obj1.body === obj2.body); // false
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
但是,会破坏原型链,并且无法拷贝属性值为function的属性
// 3. 递归
var json1={
"name":"shauna",
"age":18,
"arr1":[1,2,3,4,5],
"string":'got7',
"arr2":[1,2,3,4,5],
"arr3":[{"name1":"shauna"},{"job":"web"}]
};
var json2={};
function copy(obj1,obj2){
var obj2 = obj2 || {};
for(var name in obj1){
if(typeof obj1[name] === "object"){
obj2[name]= (obj1[name].constructor===Array)?[]:{};
copy(obj1[name],obj2[name]);
}else{
obj2[name]=obj1[name];
}
}
return obj2;
}
json2=copy(json1,json2)
json1.arr1.push(6);
alert(json1.arr1); //123456
alert(json2.arr1); //12345
- 补充题: 数组扁平化
// 递归
function flatten(arr){
var res = [];
for(var i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
res = res.concat(flatten(arr[i]));
}else{
res.push(arr[i]);
}
}
return res;
}
CVTE笔试 7.20
-
回溯算法
-
下面的输出是什么?
var array1 = Array(3);
array1[0] = 2;
var result = array1.map(elem => '1');
// ['1', empty * 2]
- 下面的输出是什么?
var setPerson = function(person) {
person.name = 'kevin';
person = {name: 'Nick'};
console.log(person.name); // Nick
person.name = 'Jay';
console.log(person.name); // Jay
}
var person = {name: 'Alan'};
setPerson(person);
console.log(person.name); // Kevin
- 下面的输出是什么?
var execFunc = () => console.log('a');
setTimeout(execFunc, 0);
console.log('000');
execFunc = () => console.log('b');
// '000', 'a'
补充:setTimeout无法使用含参函数参数
window.setTimeout(hello(userName),3000);
这将使hello函数立即执行,并将'返回值'作为调用句柄传递给setTimeout函数
// 方法1:
使用'字符串形式'可以达到想要的结果:
window.setTimeout("hello(userName)",3000);
但是,此处的username变量必须处于全局环境下
// 方法2:
function hello(_name){
alert("hello,"+_name);
}
// 创建一个函数,用于返回一个无参数函数
function _hello(_name){
return function(){
hello(_name);
}
}
window.setTimeout(_hello(userName),3000);
使用_hello(userName)来返回一个不带参数的函数句柄,从而实现了参数传递的功能
- 下面的输出是什么?
for(var i = {j: 0}; i.j < 5; i.j++) {
(function(i){
setTimeout(function() {
console.log(i.j);
}, 0);
})(JSON.parse(JSON.stringify(i)));
}
// 0, 1, 2, 3, 4
for(var i = {j: 0}; i.j < 5; i.j++) {
(function(i){
setTimeout(function() {
console.log(i.j);
}, 0);
})(i);
}
// 5, 5, 5, 5, 5
- Generator
- line-height
- FileReader
- 如何判断x为数组
- npm依赖包的版本号
- attachEvent, detachEvent, dispathEvent
阿里飞猪1面 7.20
- 自我介绍 + 项目介绍(难点)
- React相关知识
- 生命周期
- diff算法及时间复杂度
- refs
- React-router原理
- Redux和Relay的了解
- Node的了解
- Webpack的了解(如何使用)
- typeof操作符的返回值(undefined, number, string, boolean, object, function, symbol)
- ES6的了解程度
- var,let,const区别
- const a = []; a.push(1); 允许吗?
- Symbol的用处(避免属性名冲突)
- 除get和post之外,HTTP的请求方法还有哪些
- HTTP的状态码有哪些
- 从输入网址到页面呈现的过程
- DOMContentLoad和Load的区别
- Flex布局
- 客户端的存储方法?localStroage和sessionStorage的区别
- HTML5点击延迟事件
- 移动端前端开发的了解
- 前端性能优化的方法
- 前端性能工具
- 平常怎么学习前端?
- 提问
作业帮7.9
- Webpack的了解
- React的diff算法
- 单向数据流
- MVC和MVVM的区别
- ES6了解程度(let,const,Generator,Promise)
- JS异步方法及回调地狱
- Node、MongoDB了解多少
- 关系型和菲关系型数据库的区别
- CSS的position属性有哪些
- 左右定宽,中间自适应的多种CSS布局方法
- 前端的性能优化
- HTTP状态码
作业帮 2018
1.如何进行输入去重?
// 方法1:
function nonDup(arr){
var res = [];
for(var i = 0; i < arr.length; i++) {
if(res.indexOf(arr[i]) === -1) {
res.push(arr[i]);
}
}
return res;
}
// 方法2:
function nonDup(arr){
var res = new Set(arr);
return [...res];
}
// 方法3:
function nonDup(arr){
return arr.filter((elem, index) => {
return index === arr.indexOf(elem);
});
}
// 方法4:
Array.prototype.uniq = function () {
var hasNaN = false;
for(var i = 0; i < this.length; i++){
if(this[i] !== this[i]) hasNaN = true;
for(var j = i+1; j < this.length;){
if(this[i] === this[j] ||(hasNaN && this[j] !== this[j])){
this.splice(j,1);
}else{
j++;
}
}
}
return this;
}
2.实现鼠标滑过头像显示简介
<!DOCTYPE html>
<html>
<head>
<style>
.div1{
width:100px;
height:100px;
background-color:red;
border-radius: 50px;
}
.div2{
width:100px;
height:200px;
margin-top: 10px;
background-color:black;
display: none;
}
</style>
</head>
<body>
<div class='div1'></div>
<div class='div2'></div>
<script type="text/javascript">
var d1 = document.getElementsByClassName('div1')[0];
var d2 = document.getElementsByClassName('div2')[0];
var timer;
d1.addEventListener('mouseenter',function(){
timer = window.setTimeout(function(){d2.style.display="block"},300);
})
d1.addEventListener('mouseout',function(){
window.clearTimeout(timer);
d2.style.display="none";
})
</script>
</body>
</html>
转载自:https://juejin.cn/post/6844903657088122887