今天发的文章是先行者计划成员-james的亲身经历,里面涉及很多前端开发及js的基础知识,相信对于新人面试会很有帮助。所以在取得原作者同意之后在公众号发出来,希望让更多的人看到。
下面是正文:
// ------------------------ //
之前找工作总是“没心没肺”,总觉得自己可以的,除了简历,基本没准备过面试题。这次真是被面的体无完肤,深刻认识到基础的重要性,大体总结一下经历过的面试题,简单梳理一下。
首先,如果面试的是前端,需要深刻认识的一点是,考察范围为html|css|js(es6),所以node,java等后台语言不必过多纠结,如果有相关项目那当然是甚好。接下来就基础方向总结一下。
首先css方向
1.盒模型
盒模型有两种,标准模型(box-sizing:content-box)和IE模型(box-sizing:border-box)。假设页面有一个div,其样式如下:
div { width: 50px; height: 50px; background: #ff00ff; border: 1px solid #ffff00; padding: 20px 10px; margin: 20px; }
标准模型下,盒子的宽度为50px+(1*2)px+(10*2)px=72px,高度为50px+(1*2)px+(20*2)px=92px,也就是默认把border和padding算在了盒子最后的宽高内。
IE模型下,盒子的宽度为50px,高度为50px,也就是在某一方向的(padding+border)*2小于盒子的width时,最后的宽高依然等于盒子原始的width和height,如果某一方向的(padding+border)*2大于盒子的width时,此时宽高计算方式为(padding+border)*2。
除了模型本身外需要关注的一点就是margin。如果盒子是上下结构,则之间的间距为拥有较大margin的盒子,如果是左右结构,则间距为两个盒子的margin值相加。
2.BFC
BFC(Block formatting context)直译为"块级格式化上下文"。最大的特点为它是一个独立的渲染区域,并且与这个区域外部毫不相干。这个话题可以由盒模型中上下margin重叠的问题引出。触发BFC的方式如下
float
的值不为none
position
的值不为static
或者relative
display
的值为 table-cell
, table-caption
, inline-block
, flex
, inline-flex
overflow
的值不为visible
通常我喜欢的方式为浮动,display:inline-block和overflow:hidden。可以通过一个例子来理解BFC的独立性,如下所示
<style> p{ margin: 30px; height: 20px; line-height: 20px; background: red; } </style> <p>我是p1</p> <p>我是p2</p>
两个块级元素p设置了margin为30px,此时可能我们的需求为上下间距(30px+30px),这种情况就可以通过创建BFC解决,代码如下:
<style> div{ overflow: hidden; } p{ margin: 30px; height: 20px; line-height: 20px; background: red; } </style> <div> <p>我是p1</p> </div> <p>我是p2</p>
我们为第一个p标签外层加了一个div,并且样式为overflow:hidden;也就创建了一个BFC盒子,此时两个p标签的间距就变为了第一个p标签在所属的BFC内的底部margin值30px加上第二个p标签距离顶部的margin值30px,最终也就变为了60px。
3.水平垂直居中(盒子宽高可以随意更改,也就是盒子宽高不固定的居中方式)
方法1:(通过定位,外层和内层盒子宽高都不固定)
<style> div{ position: relative; } .inner{ position: absolute; margin: auto; top: 0; left: 0; right: 0; bottom: 0; } </style> <div> <div class="inner"> </div> </div>
方法2:(table-cell)
<style> div{ display: table-cell; vertical-align: middle; text-align: center; } .inner{ vertical-align: middle; display: inline-block; } </style> <div> <div class="inner"> </div> </div>
方法3:(flex)
<style> div{ display: flex; align-items: center; justify-content: center; } </style> <div> <div class="inner"> </div> </div>
方法4:(translate)
<style> div{ position: relative; } .inner{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } </style> <div> <div class="inner"> </div> </div>
4.移动端rem
首先1rem的值为页面根节点html的font-size值。移动端为了适配不同机型,所以通常会采用rem来定义页面节点尺寸。定义方式通常有两种,第一种:通过js来控制;第二种:通过css媒体查询来控制。两种方式各有优缺点。通过js来控制,会把浏览器宽度分割成制定的份数,每份定义为1rem,这样做的好处是能比较精确的控制元素尺寸,但是也有缺点,就是需要提前加载这段适配js,不可避免会导致白屏时间。第二种方式首先是直接加载的,但是媒体查询的精确度就不是很高了,通常我们都是通过比例给出一个合适的值。
再来看看js的
1.闭包
最常见的例子为下列两个,代码如下:
for(var i=0,l=5;i<l;i++){ setTimeout(function(i){ console.log(i); // 5,5,5,5,5 },0) } // 改写成正常输出 for(var i=0,l=5;i<l;i++){ (function a(i){ setTimeout(function(){ console.log(i); // 0,1,2,3,4 },0) })(i) }
2.this指针
var name = 1; var util = { name: 2, getName: function(){ return this.name; }, sub: { name: 3, getName: function(){ console.log(this); return this.name } } } var a = util.getName; var b = util.sub; console.log(a()); // 1 a的this为window,所以为window.name console.log(util.getName()); // 2 util.name为2 console.log(b.getName()); // 3 // b的this为sub,sub.name = 3 console.log(util.sub.getName()); // 3 getName为sub的直接调用,所以也为sub.name
通常意义上this指针指向为最后调用它的对象。这里需要注意的一点就是如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例,例子如下:
function getName(){ this.name = 1; return {}; // 返回对象 } var a = new getName; console.log(a.name); //undefined function getName(){ this.name = 1; return 2; // 返回非对象 } var d = new getName; console.log(d.name); //1
3.事件
事件分为捕获和冒泡,阻止默认和阻止冒泡都是有兼容性的,兼容代码如下:
function preventDefa(e){ if(window.event){ //IE中阻止函数器默认动作的方式 window.event.returnValue = false; }else{ //阻止默认浏览器动作(W3C) e.preventDefault(); } } function stopBubble(e) { if(e && e.stopPropagation) { //非IE e.stopPropagation(); } else { //IE window.event.cancelBubble = true; } }
其次为原生事件的兼容,代码如下:
function addEvent(){ var arg0 = arguments[0], arg1 = arguments[1], arg2 = arguments[2]; if (arg0.addEventListener) { arg0.addEventListener(arg1, arg2, false); }else if(arg0.attachEvent) { // ie arg0.attachEvent('on' + arg1, arg2); }else{ arg0['on' + arg1] = arg2; } };
5.原型链
function Parent(){ this.name = 'james'; } Parent.prototype.getName = function () { console.log(this.name); } var newPeople = new Parent(); function Son(){ // 继承静态方法 Parent.call(this); } // 继承原型 Son.prototype = new Parent().__proto__; // 修复指向 Son.prototype.constructor = Son; // 下列4个均为true console.log( newPeople.__proto__ === Parent.prototype ); console.log( Parent.prototype.__proto__ === Object.prototype ); console.log( newPeople instanceof Parent ); console.log( newPeople instanceof Object );
首先子类继承父类需要从静态方法和原型链两层上实现继承。通过call引用了父类的this,在原型挂载时需要注意指向应该是一个父类的实例,而不是直接Parent.prototype,存在引用问题。当指向实例后需要注意prototype上默认挂载的constructor属性需要修正到子类构造函数上。
在例子的下方有4句console,前两句展示了原型链的含义,最终指向为Object对象。后两句阐述了instanceof的含义,即判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。
6.call,apply,bind
首先这3个都是用来改变this指针用的,call和apply是立即执行,bind只是为绑定,需要调用才会执行,call和apply的参数形式也有所不同call的第二个参数为列举的一个个参数,apply为数组。面试中有问怎么实现一个bind方法,也就是只绑定this指向,简单实现代码如下:
Function.prototype.bind = function(that){ var _this = this, args = Array.prototype.slice.call(arguments,1); return function(){ return _this.apply(that,args) } }
思路:首先认识到bind为Function下的方法,其次拿到参数,最后由于需要执行才有效,所以返回一个函数。
除了这些外接下来基本考察的就是数组了(对象考察较少),这里列举几个
1.数组去重
new Set([...arr])
es5实现方式为
function unique(arr) { var n = []; for (var i = 0; i < arr.length; i++) { if (n.indexOf(arr[i]) == -1) n.push(arr[i]); } return n; }
2.判断是否为数组
Object.prototype.toString.call(arr)=='[object Array]'
3.取出两个数组的相同项
let arr1 = [1,3,4,5]; let arr2 = [1,4,6]; let getSome = arr1.filter(item=>{ return arr2.includes(item) }); console.log(getSome); // [1,4]
以上为基础部分考察最多的地方。
除此之外还有一些其它问题,这里简单罗列下:
1.css3实现一个三角形,实现原理是什么;
2.css3透明opacity,以及避免影响子元素的rgba表示方式,还有ie的hack方式;
3.js帧动画,如果为定时器,则为每秒60帧动画最流畅;
4.求一个数组的最大连续子集,求一个数组的和最大的子集,二维数组遍历如果采用从边上环形绕圈的方式,也就是m*n数列arr,从arr[0][0]-arr[0][m]-a[n][m]-a[n][0]-a[1][0]...这样等,所以数组这块的内容需要多练习;
5.跨域原理和常见跨域方式;
6.函数柯粒化及其实现;
7.性能优化;
到这里基本遍是基础部分大多数的问题了。接下来说一下除了基础外的部分内容
1.AMD,CMD,COMMON的区别和一些原理(例如怎么实现的按需加载);
2.vue的原理以及生命周期,父子组件通信,vuex的原理;
3.react生命周期,父子组件通信;
4.vue双向绑定原理;
5.对于构建工具的了解和常用的npm包有哪些;
6.对于es6的掌握程度,尤其如promise的理解等;
7.对于后台语言的接触;
8.个人职业规划或者最近几年的规划;
9.参照你的项目做一些提问,例如亮点,用到的技术栈等;
谨记基础对于一场面试成功与否的重要性~
本文分享自微信公众号 - web前端教室(webfeel),作者:James
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2018-04-30
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句