前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【投稿】记一次前端面试~James

【投稿】记一次前端面试~James

作者头像
web前端教室
发布2018-07-30 11:49:51
5110
发布2018-07-30 11:49:51
举报
文章被收录于专栏:web前端教室

今天发的文章是先行者计划成员-james的亲身经历,里面涉及很多前端开发及js的基础知识,相信对于新人面试会很有帮助。所以在取得原作者同意之后在公众号发出来,希望让更多的人看到。

下面是正文:

// ------------------------ //

之前找工作总是“没心没肺”,总觉得自己可以的,除了简历,基本没准备过面试题。这次真是被面的体无完肤,深刻认识到基础的重要性,大体总结一下经历过的面试题,简单梳理一下。

首先,如果面试的是前端,需要深刻认识的一点是,考察范围为html|css|js(es6),所以node,java等后台语言不必过多纠结,如果有相关项目那当然是甚好。接下来就基础方向总结一下。

首先css方向

1.盒模型

盒模型有两种,标准模型(box-sizing:content-box)和IE模型(box-sizing:border-box)。假设页面有一个div,其样式如下:

代码语言:javascript
复制
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的独立性,如下所示

代码语言:javascript
复制
<style>
	p{
		margin: 30px;
		height: 20px;
		line-height: 20px;
		background: red;
	}
</style>
<p>我是p1</p>
<p>我是p2</p>

两个块级元素p设置了margin为30px,此时可能我们的需求为上下间距(30px+30px),这种情况就可以通过创建BFC解决,代码如下:

代码语言:javascript
复制
<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:(通过定位,外层和内层盒子宽高都不固定)

代码语言:javascript
复制
<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)

代码语言:javascript
复制
<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)

代码语言:javascript
复制
<style>
	div{
		display: flex;
		align-items: center;
		justify-content: center;
	}
</style>
<div>
	<div class="inner">

	</div>
</div>

方法4:(translate)

代码语言:javascript
复制
<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.闭包

最常见的例子为下列两个,代码如下:

代码语言:javascript
复制
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指针

代码语言:javascript
复制
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还是指向函数的实例,例子如下:

代码语言:javascript
复制
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.事件

事件分为捕获和冒泡,阻止默认和阻止冒泡都是有兼容性的,兼容代码如下:

代码语言:javascript
复制
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; 
	} 
} 

其次为原生事件的兼容,代码如下:

代码语言:javascript
复制
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.原型链

代码语言:javascript
复制
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指向,简单实现代码如下:

代码语言:javascript
复制
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.数组去重

代码语言:javascript
复制
new Set([...arr])

es5实现方式为

代码语言:javascript
复制
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.判断是否为数组

代码语言:javascript
复制
Object.prototype.toString.call(arr)=='[object Array]'

3.取出两个数组的相同项

代码语言:javascript
复制
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.参照你的项目做一些提问,例如亮点,用到的技术栈等;

谨记基础对于一场面试成功与否的重要性~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 web前端教室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档