前端面试题100道,内含答案(大厂校招秋招1)

一.css的居中方式

1.水平居中:

(1)内联元素(利用 text-align: center 可以实现在块级元素内部的内联元素水平居中)
(2)块级元素(通过把固定宽度块级元素的margin-leftmargin-right设成automargin: 0 auto;
(3)多块级元素

A.利用inline-block(设置块级元素的显示类型为inline-block和父容器的text-align属性)
B.利用display: flex(弹性布局。设置弹性盒子元素在主轴(横轴)方向上的对齐方式,子元素水平居中显示)(display: flex;justify-content: center;

2.垂直居中:

(1)单行内联元素(设置内联元素的高度(height)和行高(line-height)相等,从而使元素垂直居中.height: 120px;line-height: 120px;

(2)多行元素
A. 利用表布局(父元素:display: table;子元素:display: table-cell;vertical-align: middle;
B.利用flex布局(父元素:display: flex;flex-direction: column;justify-content: center;
C.利用“精灵元素”(父容器内放一个100%高度的伪元素,让文本和伪元素垂直对齐

(3)块级元素
A.固定高度的块级元素(绝对定位元素距离顶部50%,并设置margin-top向上偏移元素高度的一半)
B. 未知高度的块级元素(CSS3中的transform属性向Y轴反向偏移50%.父级相对定位。子级绝对定位;top:50%;transform:translateY(-50%)😉

3.水平垂直居中:

(1)固定宽高元素(通过margin平移元素整体宽度的一半)
(2)未知宽高元素

A.利用2D变换,在水平和垂直两个方向都向反向平移宽高的一半。父级相对定位。子级绝对定位;top:50%;left: 50%;transform:translate(-50%,-50%);)
B.利用flex布局(父元素:display: flex;justify-content: center;align-items: center;)

二.px,em,rem,%

px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的(引自CSS2.0手册)
   特点:IE无法调整那些使用px作为单位的字体大小;
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。(引自CSS2.0手册) 。任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。
	特点:em的值并不是固定的;em会继承父级元素的字体大小。
rem是CSS3新增的一个相对单位。使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。1rem等于html根元素设定的font-size的px值。
总结:如果你的用户群都使用最新版的浏览器,那推荐使用rem,如果要考虑兼容性,那就使用px,或者两者同时使用。em是以自身父容器为参考对象的,而rem直接以HTML为参考对象的,在多层嵌套的情况下使用em很容易出现问题。所以rem更适合移动式开发。

三.display的值和作用元素

1、none;元素不会显示
2、inline;内联元素
3、block;块级元素
4、inline-block;行内块元素

四.路由跳转的方式

1、router-link

不带参数

<router-link :to="{name:'home'}"> 
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name  
// 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。

params传参

<router-link :to="{name:'home', params: {id:1}}">	
// params传参数 (类似post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id" 
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留	

query传参

<router-link :to="{name:'home', query: {id:1}}">
// query传参数 (类似get,url后面会显示参数)

2、 this.$router.push() (函数里面调用)

不带参数

this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})	

query传参

this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})	

params传参

this.$router.push({name:'home',params: {id:'1'}})  // 只能用 name

3、this.$router.replace() (用法同上,push)

4、this.$router.go(n)

总结 : 区别

this.$router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面

this.$router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)

this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数

五.vue生命周期的理解

Vue实例从创建到销毁的过程,就是生命周期。详细来说也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程

1、beforeCreate(Vue中的data和方法都是去不到的,并且是在wath之前执行)
2、created(可以获取Vue的data,调用Vue方法,获取原本HTML上的直接加载出来的DOM,但是无法获取到通过挂载模板生成的DOM(例如:v-for循环遍历Vue.list生成li))
3、beforeMount(在挂载开始之前被调用:相关的 render 函数(模板)首次被调用。)
4、mounted(这里为止,挂载到实例上了,我们可以获取到li的个数了)
5、beforeUpdate(数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。更改Vue的任何数据,都会触发该函数)
6、updated(数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。数据更新就会触发(vue所有的数据只有有更新就会触发),如果想数据一遍就做统一的处理,可以用这个,如果想对不同数据的更新做不同的处理可以用nextTick,或者是watch进行监听)
7、beforeDestroy(实例销毁之前调用)
8、destroyed(Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。)

钩子的一些实战用法:

1.用定时器来做异步函数( setTimeout)
2.Vue.nextTick对异步函数的结果进行操作( this.$nextTick),改变数据时,各自触发各自的方法

更详细的讲解(戳这里)

六.vue数据双向绑定的原理,用了什么设计模式(web高级)

vue.js采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
obj :待修改的对象,prop :带修改的属性名称,descriptor :待修改属性的相关描述

<script>
var obj = {}
var returnVal = ""
// 利用defineProperty去劫持更新
// 第三个参数  数据描述  存取器的描述
Object.defineProperty(obj, "age", {
    get:function () {
        return returnVal
    },
    set:function (newValue) {
        returnVal = newValue
         
    }
})
</script>

随文本框输入文字的变化,txtspan 中会同步显示相同的文字内容;在js或控制台显式的修改 obj 中 name 的值
v-model:实现双向数据绑定。

<div id="app">
	<input type="text" v-model="msg">
	{{msg}}
	<button v-on:click="add()">按钮</button>
</div>		
<script src="js/vue.js"></script>
<script>
	new Vue({
		el:'#app',
		data:{
			msg:0
		},
		methods:{
			add(){
				this.msg=this.msg+1
			}
		}
	})
</script>

七.数组去重

1.双重for循环去重

function noRepeat1(arr){
    for(var i=0; i<arr.length; i++){ // 第一层for用来控制循环的次数
        for(var j=i+1; j<arr.length; j++){ //第二层for 用于控制与第一层比较的元素
            if(arr[i] == arr[j]){   
                arr.splice(j,1);  //删除后面的 即第 j个位置上的元素  删除个数 1 个
                j--;
            }
        }
    }
    return arr;
}

2.单层for循环

function norepeat(arr){
    arr.sort();//先排序让大概相同的在一个位置,sort排序是把元素当字符串排序的 它和可能排成 1 1 10 11 2 20 3 ... 不是我们想要的从小到大
    for(var i = 0; i < arr.length-1;i++){ //还是两两比较 一样删除后面的
        if(arr[i]==arr[i+1]){
            arr.splice(i,1);
            //i-- 和j--同理
            i--;
        }
    }
    return arr;
}

3.利用 indexOf 属性

function noRepeat2(arr){
    var newArr = [];//用一个空数组去存首次 出现的元素 
    for(var i = 0; i < arr.length; i++){
        if(newArr.indexOf(arr[i]) == -1){
                    newArr.push(arr[i]);
            }
    }
    return newArr;
}
PS:indexOf是返回某个指定的字符在字符串中出现的位置,如果没有就会返回-1 .因此我们可以很好的利用这个属性 当返回的是 -1时 就让其存入数组

4.利用对象的思想

function norepeat3(arr) {
     var obj = {};
     var newArr = [];
     for(var i = 0; i < arr.length; i++) {
         if(obj[arr[i]] == undefined) {
             newArr.push(arr[i]);
             obj[arr[i]] = 1;
         }
     }
     return newArr;
}
PS: 如果对象里没有这个属性的话就会返回undefined 。利用这个原理当返回的是undefined时 让其放入数组 然后在给这个属性赋值

5.循环比较(与有方法一相似,但更麻烦)

var newArr = [];   
for(var i=0; i<arr.length-1;i++){ //控制外循环     
    for(j=i+1;j<arr.length;j++){ //内存循环 只比较后面的
        if(arr[i]==arr[j]){ //如果相等就让其值等于0
            arr[j]=0;
        }
    }	        
    if(arr[i]==0){//去除值为0的
        continue;
    }else{	            
        newArr.push(arr[i]);//放入新的数组
    }
}
PS:如果相等的让后面的元素值为0 最后在输出的时候删除为0的 这个前提是你的数据里不能有0 但是凡事可以变通你可以设置任何值替代这个0 这个方法是我当时想到实现的所以没有进行很好的优化

八.统计字符串中出现最多的字符

function countStr(str){  // 形参接受
	var myobj = {}; // 存储出现最多的字符
	for( var i=0, len=str.length,num; i<len; i++ ){
		num= str.charAt(i) 
		if( myobj[num] ){ // 保存次数
			myobj[num]++;
		}else{
			myobj[num]=1;
		};
	};
	console.log(myobj)
	var n= 0,item=null;
        for(var k in myobj){
            if( myobj[k] > n ){
                n = myobj[k];
                item = k;
            }
        }
	return item+':'+n
};
countStr('哈哈哈呵呵');  // 实参传参
 // {哈: 3, 呵: 2}
 // "哈:3"

九.js垃圾回收机制

垃圾回收的必要性:

1、JS不像C/C++,他有自己的一套垃圾回收机制(Garbage Collection)。
2、由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。
3、JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
4、JavaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了

垃圾回收原理浅析

1、标记清除

  这是javascript中最常用的垃圾回收方式。
  垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。

2、引用计数

  另一种不太常见的垃圾回收策略是引用计数。
  引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,减1。它就会释放那些引用次数为0的值所占的内存。
  

更详细的讲解(戳这里)

十.原型、原型链

原型:

所有引用类型(函数,数组,对象)都拥有__proto__属性(隐式原型),
所有函数拥有prototype属性(显式原型)(仅限函数)

原型链:

	当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或者方法,
	就会去关联的prototype那里寻找。如果prototype没有,就会去prototype关联的前辈prototype那里寻找,
	如果没有,依次向上寻找。
	依次类推,直到prototype....prototype为undefined。从而形成了所谓的“原型链”

总结:

1.查找属性,如果本身没有,则会去__proto__中查找,也就是构造函数的显式原型中查找,如果构造函数中也没有该属性,因为构造函数也是对象,也有__proto__,那么会去它的显式原型中查找,一直到null,如果没有则返回undefined
   2.p.__proto__.constructor  == function Person(){}
   3.p.___proto__.__proto__== Object.prototype
   4.p.___proto__.__proto__.__proto__== Object.prototype.__proto__ == null         
   5.通过__proto__形成原型链而非protrotype

在这里插入图片描述
1、isPrototypeOf()方法

判断一个prototype对象是否存在于另一个对象的原型链中。返回值true:是;返回值false:否
    如: console.log(car1.isPrototypeOf(car11));//a.isPrototypeOf(b)方法  判断a是否是b的父级 

2、hasOwnProperty()

 判断是自有属性还是继承的
   console.log(s1.hasOwnProperty('sum'))

3、 instanceof

判断实例对象是否是某个构造函数的实例对象。
      console.log(p1 instanceof Product)

更多讲解戳这里

拓展更多面试题(100道前端面试题练手):

1、前端近年面试题(1)
2、前端近年面试题(2)
3、前端近年面试题(3)
4、前端近年面试题(4)
5、前端近年面试题(5)
6、前端近年面试题(6)
7、前端近年面试题(7)
8、前端近年面试题(8)
9、前端近年面试题(9)

  • 6
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值