摘要:为了避免它,只需分配将要使用的必要构造函数。示例对于此示例,就需要保持父构造函数继续正常工作。结论手动设置或更新构造函数可能会导致不同且有时令人困惑的后果。为了防止它,只需在每个特定情况下定义构造函数的角色。
hr小姐姐说一共有1轮笔试 + 3轮技术面 + 1轮hr面,面试地点在中关村天使大厦,岗位是1-3年前端笔试
笔试分为多选 简答 判断 手写代码四部分,下面只写了印象比较深的几道。
多选1、position为relative的元素可以使用top和left进行定位吗
答:可以。
我自己没见过这种写法,就没敢选,然后错。
2、以下哪个是加密算法
答:RES、DES。
md5不算加密算法。
这部分题目是给出代码,让你写输出
1、
setTimeout(() => {console.log(1)}) const promise = new Promise(resolve => { setTimeout(() => {console.log(2)}) resolve() }) promise.then(() => {console.log(3)})
答:312。
考察macro/micro task
2、
for(var i = 1; i < 3; i++) { setTimeout(() => {console.log(i)}) }
答:3 3
考察异步,这个题简直是必考题
变种:
for(let i = 1; i< 3; i++) { setTimeout(() => {console.log(i)}) }
答:1 2
用let的话就会每轮循环都是一个崭新的i
3、
function A() { this.a = "hi" console.log(this.a) } A.prototype.a = "hello" const a = new A() console.log(a.a)
答:hi hi
考察原型链,A.prototype.a = "hello",修改的是a原型上的a属性,与a本身的a属性无瓜。
浏览器运行截图
4、
[] == false
答:true
考察类型转换,双等运算两边先转换为Number
5、
[1,2,3].push(4)
答:4
考察常用函数返回值, 数组的push和unshift都返回最新数组的长度
判断就5道题,挺简单的,没啥印象
手写代码手写一个节流函数,这个网上一搜一大把就不说了
一面笔试写了大概30-40分钟,一面的面试官就来了,看答题情况的时候顺便要求介绍一下自己,然后针对题目做了一些讲解,然后开始问问题。
1、再手写一个防抖,我写了一个第一次触发事件不会调用回调的,面试官又问如果希望首次也会调用怎么写,代码如下
var debounce = function(fn, delayTime, immediate) { var timeId; return function() { var context = this, args = arguments; if(immediate) { var callNow = !timeId; if(callNow) { fn.apply(context, args); } } timeId && clearTimeout(timeId); timeId = setTimeout(function() { fn.apply(context, args); }, delayTime) } }
然后还聊了一下时间戳和定时器的方式实现节流的不同,需要注意箭头函数是不可以使用arguments对象的,所以返回的函数必须要写成return function() {}
2、有什么实现深拷贝的方法吗
我一开始以为他说api,就回答JSON.parse(JSON.stringfy())和MessageChannel,他问有什么问题吗。我说不能解决复制函数和环的问题。他又问那你能自己实现一个吗,继续手写代码
function isObject(obj) { return obj !== null && typeof obj === "object" } function cloneDeep(obj) { let result = {} const keys = Object.keys(obj); for(let i = 0, len = keys.length; i < len; i++) { if(isObject(obj[keys[i]])){ result[keys[i]] = cloneDeep(obj[keys[i]]) } else { result[keys[i]] = obj[keys[i]] } } return resultset }
写完之后他又问我应该如何判断一个变量是数组,答Array.isArray()和Object.prototype.toString.call(arr) === "[object Array]",回来反思发现可能是写深拷贝的时候忘记了数组的情况,然后他才问的判断数组。
3、如何用css画一个三角形
答:heigh: 0; width: 0; border: 100px, solid, transparent; border-bottom: 100px, solid, yellow;
4、怎么实现垂直居中
答:position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); 还有flex;
5、简单说一下前端优化策略
答:减少请求,他:具体应该怎么减少,我:比如图片懒加载,配置svg-sprite-loader打包一张svg图面,然后就是减少dom操作,减少浏览器回流重绘次数,减少作用域链的查找,减少对象的深度查找。他:还有吗。我:暂时想不起其它了
优化涉及的东西太多了,以后再多带带总结吧。
6、new一个对象的时候发生了什么
这个问题是讲解笔试简答第三题时候问的
正确答案:1.创建一个空对象; 2.设置创建对象的__proto__属性的值为构造函数的prototype属性的值; 3.将第一步创建的空对象作为this的上下文,执行构造函数代码; 如果构造函数没有返回对象,那么返回this
7、看你简历上写最近在看vue源码,那你知道nextTick咋实现的吗
答:2.6的版本是promise,mutationObserver,setTimeout,setImmediate
至此面试官说一面差不多就到这里,算法啥的留给二面吧,他给我的一面评价是知识广度不够(因为笔试错了比较多),但是感觉人比较有灵性,可以进入二面,然后就去叫下一个boss了。
二面 二面面试官看起来比前一个要严厉好多,以为要问一些算法题,结果"一面反馈基础不够扎实,那我就再问一点" "GG"
1、import和require的区别
答:import输出引用,require输出拷贝。他:还有吗。 我:不知道了。他:还有require是运行时加载,import是编译时输出接口。
2、说一下浏览器的事件传播机制
答:不知道
正确答案: 事件传播分为三个阶段:捕获,目标对象,冒泡。其中捕获是事件对象从window派发到目标对象父级的过程;目标阶段是事件对象派发到目标元素时的阶段,如果事件类型指示不冒泡,那事件传播在此阶段终止;冒泡和捕获相反,是以目标对象父级到window的过程。
3、手写一个bind
答:不知道。
平时用的都是call和apply来改this,bind只用过一两次,手写call也看过,但是我连bind的参数是啥都没印象,写个锤子。
正确答案:
///使用call Function.prototype.cvBind = function() { var self = this var context = [].shift.call(arguments) var args = Array.from(arguments) return function() { return self.call(context, ...args) } } // 不用call Function.prototype.cvBind = function() { var context = [].shift.call(arguments) context.fn = this var args = [] var argument = [].slice.call(arguments, 0) for(var i = 0, len = argument.length; i < len; i++) { args.push("argument[" + i + "]") } return function() { var result = eval("context.fn(" + args + ")") delete context.fn return result } } // 测试 var obj = { a: "local", log: function(x, y) { console.log(this.a, x, y) } } var a = "window" obj.log("arg1", "arg2") var func = obj.log.cvBind(window, "arg1", "arg2") func()
需要注意不用call的版本需要拷贝一次arguments,不然return的函数中args数组里都是undefined,上面的代码不考虑参数是引用类型变量。
4、写一个继承
答:不知道
正确答案:
4.1类式继承,通过构造函数实现继承
//父类 function Parent(name) { this.name = name || "parent" } Parent.prototype.say = function() { return this.name } //子类 function Child() {}
4.1.1 父类对象继承
Child.prototype = new Parent("child") var child = new Child() child.say()
这种继承方式,子类继承父类自身属性和父类原型上的属性,但是缺点在于初始化父类对象指给子类原型时,并不能确定父类构造函数的初始化参数。
4.1.2 改造子类构造函数
function Child() { Parent.apply(this, arguments) }
弟中弟方法,只能继承父类自身方法
4.1.3 共享原型
Child.prototype = Parent.prototype
弟中弟中弟,共享一个原型,子类修改会影响父类(然而面试的时候脑子里浮现的就是这种)
4.1.4 临时构造函数
function inherit(Child, Parent) { var F = function() {} F.prototype = Parent.protoType Child.protoype = new F() }
利用一个空函数F()充当子类父类之间的代理,既可以实现父类原型属性的继承,也可以在子类原型上随意拓展
使用Object.create()可以达到相同效果
Child.prototype = Object.create(Parent.prototype)
4.1.5 关于protptype.constructor
整理资料的时候,发现有些在继承后又写了一句Child.prototype.constructor = Child,有些就没有。首先这个constructor时创建实例对象的构造函数的引用,然后就是这句话到底有用没用,下面是ctrl cv自MDN的两个例子以及结论
示例1:
function Parent() {}; function CreatedConstructor() {} CreatedConstructor.prototype = Object.create(Parent.prototype); CreatedConstructor.prototype.create = function create() { return new this.constructor(); } new CreatedConstructor().create().create(); // error undefined is not a function since constructor === Parent
在上面的示例中,将显示异常,因为构造函数链接到Parent。为了避免它,只需分配将要使用的必要构造函数。
function Parent() {}; function CreatedConstructor() {} CreatedConstructor.prototype = Object.create(Parent.prototype); CreatedConstructor.prototype.constructor = CreatedConstructor; // set right constructor for further using CreatedConstructor.prototype.create = function create() { return new this.constructor(); } new CreatedConstructor().create().create(); // it"s pretty fine
示例2:
function ParentWithStatic() {} ParentWithStatic.startPosition = { x: 0, y:0 }; ParentWithStatic.getStartPosition = function getStartPosition() { return this.startPosition; } function Child(x, y) { this.position = { x: x, y: y }; } Child.prototype = Object.create(ParentWithStatic.prototype); Child.prototype.constructor = Child; Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() { var position = this.position; var startPosition = this.constructor.getStartPosition(); // error undefined is not a function, since the constructor is Child return { offsetX: startPosition.x - position.x, offsetY: startPosition.y - position.y } };
对于此示例,就需要保持父构造函数继续正常工作。
结论:手动设置或更新构造函数可能会导致不同且有时令人困惑的后果。为了防止它,只需在每个特定情况下定义构造函数的角色。在大多数情况下,不使用构造函数,并且不需要重新分配构造函数。
4.2 通过复制属性实现继承
浅拷贝和4.1.3的共享原型没区别,深拷贝继承之后修改父类,子类不会改变。都有问题不过也是一种思路,顺带一提。
5、跨域有哪些解决方案
答:iframe, jsonp, cors。他:用过jsonp吗。答:没有,用的都是cors。他:那说一下cors是怎么解决跨域问题的。我:不知道。他:那请求头里有哪些相关的字段。我:(我知道你真的很给机会了但是对不起我是个菜鸡我真的)不知道。他:用过nginx吗。我:没有。
正确答案:点这里
balabala一些客套话,问我有什么问题,我说没有,然后结束。
路漫漫其修远兮认识到差距也更有前进的动力,继续加油
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/106266.html
摘要:这是一次失败的面经但是吃一堑才能长一智不是吗字节跳动校招面经前端开发岗一介绍以及项目经历吧啦吧啦此处省略字面试官会从项目经历入手,考察项目中遇到的难题,以及解决方法,强调个人的努力以及在解决过程中扮演的角色是主导还是参与。 这是一次失败的面经……但是吃一堑才能长一智不是吗? 字节跳动2019校招面经 - 前端开发岗(一) 1. 介绍以及项目经历 吧啦吧啦……此处省略10000字 面试官...
摘要:春招前端实习面试记录从就开始渐渐的进行复习,月末开始面试,到现在四月中旬基本宣告结束。上海爱乐奇一面盒模型除之外的面向对象语言继承因为是视频面试,只记得这么多,只感觉考察的面很广,前端后端移动端都问了,某方面也有深度。 春招前端实习面试记录(2019.3 ~ 2019.5) 从2019.1就开始渐渐的进行复习,2月末开始面试,到现在四月中旬基本宣告结束。在3月和4月经历了无数次失败,沮...
摘要:面试后面试后及时总结,有可能下一个面试官会问你同样的问题。同时面试官也对我的未来技术发展提出了很多建议。总的来说,四面的氛围并没有想象得那么严肃,面试官也说面试得很愉快。 ...
摘要:为什么状态需要经过最大报文段生存时间才能返回到状态虽然按道理,四个报文都发送完毕,我们可以直接进入状态了,但是我们必须假象网络是不可靠的,有可以最后一个丢失。所以状态就是用来重发可能丢失的报文。 1、TCP的三次握手和四次挥手 1.1 三次握手: 客户端请求 -> 服务器响应 -> 客户端确认收到响应,建立连接(保证网络正常) showImg(https://segmentfault....
阅读 3090·2021-11-22 09:34
阅读 590·2021-11-22 09:34
阅读 2434·2021-10-08 10:18
阅读 3367·2021-09-22 15:57
阅读 2582·2021-09-22 15:25
阅读 2394·2019-08-30 15:54
阅读 2087·2019-08-30 15:44
阅读 1796·2019-08-29 11:18