hr小姐姐说一共有1轮笔试 + 3轮技术面 + 1轮hr面,面试地点在中关村天使大厦,岗位是1-3年前端
笔试分为多选 简答 判断 手写代码四部分,下面只写了印象比较深的几道。css
一、position为relative的元素可使用top和left进行定位吗
答:能够。
我本身没见过这种写法,就没敢选,而后错。前端
二、如下哪一个是加密算法
答:RES、DES。
md5不算加密算法。vue
这部分题目是给出代码,让你写输出
一、nginx
setTimeout(() => {console.log(1)}) const promise = new Promise(resolve => { setTimeout(() => {console.log(2)}) resolve() }) promise.then(() => {console.log(3)})
答:312。
考察macro/micro task面试
二、算法
for(var i = 1; i < 3; i++) { setTimeout(() => {console.log(i)}) }
答:3 3
考察异步,这个题简直是必考题
变种:json
for(let i = 1; i< 3; i++) { setTimeout(() => {console.log(i)}) }
答:1 2
用let的话就会每轮循环都是一个崭新的isegmentfault
三、api
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属性无瓜。
浏览器运行截图跨域
四、
[] == false
答:true
考察类型转换,双等运算两边先转换为Number
五、
[1,2,3].push(4)
答:4
考察经常使用函数返回值, 数组的push和unshift都返回最新数组的长度
判断就5道题,挺简单的,没啥印象
手写一个节流函数,这个网上一搜一大把就不说了
笔试写了大概30-40分钟,一面的面试官就来了,看答题状况的时候顺便要求介绍一下本身,而后针对题目作了一些讲解,而后开始问问题。
一、再手写一个防抖,我写了一个第一次触发事件不会调用回调的,面试官又问若是但愿首次也会调用怎么写,代码以下
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() {}
二、有什么实现深拷贝的方法吗
我一开始觉得他说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]',回来反思发现多是写深拷贝的时候忘记了数组的状况,而后他才问的判断数组。
三、如何用css画一个三角形
答:heigh: 0; width: 0; border: 100px, solid, transparent; border-bottom: 100px, solid, yellow;
四、怎么实现垂直居中
答:position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); 还有flex;
五、简单说一下前端优化策略
答:减小请求,他:具体应该怎么减小,我:好比图片懒加载,配置svg-sprite-loader打包一张svg图面,而后就是减小dom操做,减小浏览器回流重绘次数,减小做用域链的查找,减小对象的深度查找。他:还有吗。我:暂时想不起其它了
优化涉及的东西太多了,之后再单独总结吧。
六、new一个对象的时候发生了什么
这个问题是讲解笔试简答第三题时候问的
正确答案:1.建立一个空对象; 2.设置建立对象的__proto__属性的值为构造函数的prototype属性的值; 3.将第一步建立的空对象做为this的上下文,执行构造函数代码; 若是构造函数没有返回对象,那么返回this
七、看你简历上写最近在看vue源码,那你知道nextTick咋实现的吗
答:2.6的版本是promise,mutationObserver,setTimeout,setImmediate
至此面试官说一面差很少就到这里,算法啥的留给二面吧,他给个人一面评价是知识广度不够(由于笔试错了比较多),可是感受人比较有灵性,能够进入二面,而后就去叫下一个boss了。
二面面试官看起来比前一个要严厉好多,觉得要问一些算法题,结果"一面反馈基础不够扎实,那我就再问一点" "GG"
一、import和require的区别
答:import输出引用,require输出拷贝。他:还有吗。 我:不知道了。他:还有require是运行时加载,import是编译时输出接口。
二、说一下浏览器的事件传播机制
答:不知道
正确答案: 事件传播分为三个阶段:捕获,目标对象,冒泡。其中捕获是事件对象从window派发到目标对象父级的过程;目标阶段是事件对象派发到目标元素时的阶段,若是事件类型指示不冒泡,那事件传播在此阶段终止;冒泡和捕获相反,是以目标对象父级到window的过程。
三、手写一个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,上面的代码不考虑参数是引用类型变量。
2019.10.29更新
由于return的是一个function(){}
而不是箭头函数,因此存在本身的arguments而不能使用闭包中的arguments,这里拷贝一遍是能够的能够,可是也能够返回一个箭头函数来直接使用父做用域中的arguments
四、写一个继承
答:不知道
正确答案:
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的共享原型没区别,深拷贝继承以后修改父类,子类不会改变。都有问题不过也是一种思路,顺带一提。
五、跨域有哪些解决方案
答:iframe, jsonp, cors。他:用过jsonp吗。答:没有,用的都是cors。他:那说一下cors是怎么解决跨域问题的。我:不知道。他:那请求头里有哪些相关的字段。我:(我知道你真的很给机会了可是对不起我是个菜鸡我真的)不知道。他:用过nginx吗。我:没有。
正确答案:点这里
balabala一些客套话,问我有什么问题,我说没有,而后结束。
认识到差距也更有前进的动力,继续加油