前言
从前端学习到找一份合适的工作,大大小小的面试必不可少,所以我对初级前端面试题进行了初步整理,也方便自己查阅,也希望对小伙伴们有所帮助!
给大家推荐一个实用面试题库
1、前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
HTML
HTML语义化
HTML语义化就是让页面内容结构化,它有如下优点
1、易于用户阅读,样式丢失的时候能让页面呈现清晰的结构。 2、有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重。 3、方便其他设备解析,如盲人阅读器根据语义渲染网页 4、有利于开发和维护,语义化更具可读性,代码更好维护,与CSS3关系更和谐 复制代码
如:
<header>代表头部 <nav>代表超链接区域 <main>定义文档主要内容 <article>可以表示文章、博客等内容 <aside>通常表示侧边栏或嵌入内容 <footer>代表尾部 复制代码
HTML5新标签
有<header>、<footer>、<aside>、<nav>、<video>、<audio>、<canvas>等... 复制代码
CSS
盒子模型
盒模型分为标准盒模型和怪异盒模型(IE模型)
box-sizing:content-box //标准盒模型 box-sizing:border-box //怪异盒模型 复制代码
标准盒模型:元素的宽度等于style里的width+margin+border+padding宽度
如下代码,整个宽高还是120px
div{ box-sizing: content-box; margin: 10px; width: 100px; height: 100px; padding: 10px; } 复制代码
怪异盒模型:元素宽度等于style里的width宽度
如下代码,整个宽高还是100px
div{ box-sizing: border-box; margin: 10px; width: 100px; height: 100px; padding: 10px; } 复制代码
注意:如果你在设计页面中,发现内容区被撑爆了,那么就先检查一下border-sizing是什么,最好在引用reset.css的时候,就对border-sizing进行统一设置,方便管理
rem与em的区别
rem是根据根的font-size变化,而em是根据父级的font-size变化
rem:相对于根元素html的font-size,假如html为font-size:12px,那么,在其当中的div设置为font-size:2rem,就是当中的div为24px
em:相对于父元素计算,假如某个p元素为font-size:12px,在它内部有个span标签,设置font-size:2em,那么,这时候的span字体大小为:12*2=24px
CSS选择器
css常用选择器
通配符:* ID选择器:#ID 类选择器:.class 元素选择器:p、a 等 后代选择器:p span、div a 等 伪类选择器:a:hover 等 属性选择器:input[type="text"] 等 复制代码
css选择器权重
!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认
CSS新特性
transition:过渡 transform:旋转、缩放、移动或者倾斜 animation:动画 gradient:渐变 shadow:阴影 border-radius:圆角 复制代码
行内元素和块级元素
行内元素(display: inline)
宽度和高度是由内容决定,与其他元素共占一行的元素,我们将其叫行内元素,例如: 、 、
等
默认宽度由父容器决定,默认高度由内容决定,独占一行并且可以设置宽高的元素,我们将其叫做块级元素,例如:
在平时,我们经常使用CSS的display: inline-block,使它们拥有更多的状态
绝对定位和相对定位的区别
position: absolute
绝对定位:是相对于元素最近的已定位的祖先元素
position: relative
相对定位:相对定位是相对于元素在文档中的初始位置
BFC
什么是BFC?
BFC格式化上下文,它是一个独立的渲染区域,让处于 BFC 内部的元素和外部的元素相互隔离,使内外元素的定位不会相互影响
如何产生BFC?
display: inline-block
position: absolute/fixed
给大家推荐一个实用面试题库
1、前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
BFC作用
BFC最大的一个作用就是:在页面上有一个独立隔离容器,容器内的元素和容器外的元素布局不会相互影响
解决上外边距重叠;重叠的两个box都开启bfc; 解决浮动引起高度塌陷;容器盒子开启bfc 解决文字环绕图片;左边图片div,右边文字容器p,将p容器开启bfc 复制代码
水平垂直居中
Flex布局
display: flex //设置Flex模式 flex-direction: column //决定元素是横排还是竖着排 flex-wrap: wrap //决定元素换行格式 justify-content: space-between //同一排下对齐方式,空格如何隔开各个元素 align-items: center //同一排下元素如何对齐 align-content: space-between //多行对齐方式 复制代码
水平居中
行内元素:display: inline-block; 块级元素:margin: 0 auto; Flex: display: flex; justify-content: center 复制代码
垂直居中
行高 = 元素高:line-height: height flex: display: flex; align-item: center 复制代码
less,sass,styus三者的区别
变量
Sass声明变量必须是『$』开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:分隔开。
Less 声明变量用『@』开头,其余等同 Sass。
Stylus 中声明变量没有任何限定,结尾的分号可有可无,但变量名和变量值之间必须要有『等号』。
作用域
Sass:三者最差,不存在全局变量的概念
Less:最近的一次更新的变量有效,并且会作用于全部的引用!
Stylus:Sass 的处理方式和 Stylus 相同,变量值输出时根据之前最近的一次定义计算,每次引用最近的定义有效;
嵌套
三种 css 预编译器的「选择器嵌套」在使用上来说没有任何区别,甚至连引用父级选择器的标记 & 也相同
继承
Sass和Stylus的继承非常像,能把一个选择器的所有样式继承到另一个选择器上。使用『@extend』开始,后面接被继承的选择器。Stylus 的继承方式来自 Sass,两者如出一辙。 Less 则又「独树一帜」地用伪类来描述继承关系;
导入@Import
Sass 中只能在使用 url() 表达式引入时进行变量插值
$device: mobile; @import url(styles.#{$device}.css); 复制代码
Less 中可以在字符串中进行插值
@device: mobile; @import "styles.@{device}.css"; 复制代码
Stylus 中在这里插值不管用,但是可以利用其字符串拼接的功能实现
device = "mobile" @import "styles." + device + ".css" 复制代码
总结
Sass和Less语法严谨、Stylus相对自由。因为Less长得更像 css,所以它可能学习起来更容易。
Sass 和 Compass、Stylus 和 Nib 都是好基友。
Sass 和 Stylus 都具有类语言的逻辑方式处理:条件、循环等,而 Less 需要通过When等关键词模拟这些功能,这方面 Less 比不上 Sass 和 Stylus
Less 在丰富性以及特色上都不及 Sass 和 Stylus,若不是因为 Bootstrap 引入了 Less,可能它不会像现在这样被广泛应用(个人愚见)
link与@import区别与选择
<style type="text/css"> @import url(CSS文件路径地址); </style> <link href="CSSurl路径" rel="stylesheet" type="text/css" / 复制代码
link功能较多,可以定义 RSS,定义 Rel 等作用,而@import只能用于加载 css;
当解析到link时,页面会同步加载所引的 css,而@import所引用的 css 会等到页面加载完才被加载;
@import需要 IE5 以上才能使用;
link可以使用 js 动态引入,@import不行
多行元素的文本省略号
overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical 复制代码
JavaScript
JS的几条基本规范
1、不要在同一行声明多个变量 2、请使用===/!==来比较true/false或者数值 3、使用对象字面量替代new Array这种形式 4、不要使用全局变量 5、Switch语句必须带有default分支 6、函数不应该有时候有返回值,有时候没有返回值 7、For循环必须使用大括号 8、IF语句必须使用大括号 9、for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染 复制代码
JS引用方法
行内引入
<body> <input type="button" onclick="alert('行内引入')" value="按钮"/> <button onclick="alert(123)">点击我</button> </body> 复制代码
内部引入
<script> window.onload = function() { alert("js 内部引入!"); } </script> 复制代码
外部引入
<body> <div></div> <script type="text/javascript" src="./js/index.js"></script> </body> 复制代码
注意
1,不推荐写行内或者HTML中插入<script>,因为浏览器解析顺序缘故,如果解析到死循环之类的JS代码,会卡住页面 2,建议在onload事件之后,即等HTML、CSS渲染完毕再执行代码 复制代码
JS的基本数据类型
Undefined、Null、Boolean、Number、String、新增:Symbol
数组操作
在 JavaScript 中,用得较多的之一无疑是数组操作,这里过一遍数组的一些用法
map: 遍历数组,返回回调返回值组成的新数组 forEach: 无法break,可以用try/catch中throw new Error来停止 filter: 过滤 some: 有一项返回true,则整体为true every: 有一项返回false,则整体为false join: 通过指定连接符生成字符串 push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项【有误】 unshift / shift: 头部推入和弹出,改变原数组,返回操作项【有误】 sort(fn) / reverse: 排序与反转,改变原数组 concat: 连接数组,不影响原数组, 浅拷贝 slice(start, end): 返回截断后的新数组,不改变原数组 splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组 indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标 reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始) 复制代码
JS有哪些内置对象
Object是JavaScript中所有对象的父对象 数据封装对象:Object、Array、Boolean、Number和String 其他对象:Function、Arguments、Math、Date、RegExp、Error 复制代码
给大家推荐一个实用面试题库
1、前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
get请求传参长度的误区
误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的
实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是来源与浏览器或web服务器,浏览器或web服务器限制了url的长度。为了明确这个概念,我们必须再次强调下面几点:
1、HTTP 协议 未规定 GET 和POST的长度限制
2、GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
3、不同的浏览器和WEB服务器,限制的最大长度不一样
4、要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte
补充get和post请求在缓存方面的区别
- get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。
- post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。
闭包
什么是闭包?
函数A 里面包含了 函数B,而 函数B 里面使用了 函数A 的变量,那么 函数B 被称为闭包。
又或者:闭包就是能够读取其他函数内部变量的函数
function A() { var a = 1; function B() { console.log(a); } return B(); } 复制代码
闭包的特征
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收制回收
对闭包的理解
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中
闭包的另一个用处,是封装对象的私有属性和私有方法
闭包的好处
能够实现封装和缓存等
闭包的坏处
就是消耗内存、不正当使用会造成内存溢出的问题
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
解决方法是:在退出函数之前,将不使用的局部变量全部删除
闭包的经典问题
for(var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); } 复制代码
这段代码输出
答案:3个3 解析:首先,for 循环是同步代码,先执行三遍 for,i 变成了 3;然后,再执行异步代码 setTimeout,这时候输出的 i,只能是 3 个 3 了 复制代码
有什么办法依次输出0 1 2
第一种方法
使用let
for(let i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); } 复制代码
在这里,每个 let 和代码块结合起来形成块级作用域,当 setTimeout() 打印时,会寻找最近的块级作用域中的 i,所以依次打印出 0 1 2
如果这样不明白,我们可以执行下边这段代码
for(let i = 0; i < 3; i++) { console.log("定时器外部:" + i); setTimeout(function() { console.log(i); }, 1000); } 复制代码
此时浏览器依次输出的是:
定时器外部:0 定时器外部:1 定时器外部:2 0 1 2 复制代码
即代码还是先执行 for 循环,但是当 for 结束执行到了 setTimeout 的时候,它会做个标记,这样到了 console.log(i) 中,i 就能找到这个块中最近的变量定义
第二种方法
使用立即执行函数解决闭包的问题
for(let i = 0; i < 3; i++) { (function(i){ setTimeout(function() { console.log(i); }, 1000); })(i) } 复制代码
JS作用域及作用域链
作用域
在JavaScript中,作用域分为 全局作用域 和 函数作用域
全局作用域
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域
函数作用域
在固定的代码片段才能被访问
例子:
作用域有上下级关系,上下级关系的确定就看函数是在哪个作用域下创建的。如上,fn作用域下创建了bar函数,那么“fn作用域”就是“bar作用域”的上级。
作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
变量取值:到创建 这个变量 的函数的作用域中取值
作用域链
一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值。
但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链
原型和原型链
原型和原型链的概念
每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去
原型和原型链的关系
instance.constructor.prototype = instance.__proto__ 复制代码
原型和原型链的特点
JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变
当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的
就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象
给大家推荐一个实用面试题库
1、前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
组件化和模块化
组件化
为什么要组件化开发
有时候页面代码量太大,逻辑太多或者同一个功能组件在许多页面均有使用,维护起来相当复杂,这个时候,就需要组件化开发来进行功能拆分、组件封装,已达到组件通用性,增强代码可读性,维护成本也能大大降低
组件化开发的优点
很大程度上降低系统各个功能的耦合性,并且提高了功能内部的聚合性。这对前端工程化及降低代码的维护来说,是有很大的好处的,耦合性的降低,提高了系统的伸展性,降低了开发的复杂度,提升开发效率,降低开发成本
组件化开发的原则
- 专一
- 可配置性
- 标准性
- 复用性
- 可维护性
模块化
为什么要模块化
早期的javascript版本没有块级作用域、没有类、没有包、也没有模块,这样会带来一些问题,如复用、依赖、冲突、代码组织混乱等,随着前端的膨胀,模块化显得非常迫切
模块化的好处
- 避免变量污染,命名冲突
- 提高代码复用率
- 提高了可维护性
- 方便依赖关系管理
模块化的几种方法
- 函数封装
var myModule = { var1: 1, var2: 2, fn1: function(){ }, fn2: function(){ } } 复制代码
总结:这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系 缺陷:外部可以睡意修改内部成员,这样就会产生意外的安全问题 复制代码
- 立即执行函数表达式(IIFE)
var myModule = (function(){ var var1 = 1; var var2 = 2; function fn1(){ } function fn2(){ } return { fn1: fn1, fn2: fn2 }; })(); 复制代码
总结:这样在模块外部无法修改我们没有暴露出来的变量、函数 缺点:功能相对较弱,封装过程增加了工作量,仍会导致命名空间污染可能、闭包是有成本的 复制代码
图片的预加载和懒加载
- 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染
- 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。预加载则会增加服务器前端压力,懒加载对服务器有一定的缓解压力作用。
mouseover和mouseenter的区别
mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave
解决异步回调地狱
promise、generator、async/await
对This对象的理解
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
Vue
vue生命周期
什么是Vue生命周期?
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期
Vue生命周期的作用是什么?
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑
Vue生命周期总共有几个阶段?
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
DOM渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
每个生命周期适合哪些场景?
生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom
v-show与v-if区别
v-show是css切换,v-if是完整的销毁和重新创建
使用 频繁切换时用v-show,运行时较少改变时用v-if
v-if=‘false’ v-if是条件渲染,当false的时候不会渲染
开发中常用的指令有哪些
v-model :一般用在表达输入,很轻松的实现表单控件和数据的双向绑定
v-html: 更新元素的 innerHTML
v-show 与 v-if: 条件渲染, 注意二者区别
使用了v-if的时候,如果值为false,那么页面将不会有这个html标签生成 v-show则是不管值为true还是false,html元素都会存在,只是CSS中的display显示或隐藏 复制代码
v-on : click: 可以简写为@click,@绑定一个事件。如果事件触发了,就可以指定事件的处理函数 v-for:基于源数据多次渲染元素或模板块 v-bind: 当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
语法:v-bind:title="msg" 简写::title="msg" 复制代码
绑定class的数组用法
对象方法 v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
数组方法 v-bind:class="[class1, class2]"
行内 v-bind:style="{color: color, fontSize: fontSize+'px' }"
组件之间的传值通信
父组件给子组件传值
使用props,父组件可以使用props向子组件传递数据
父组件vue模板father.vue
<template> <child :msg="message"></child> </template> <script> import child from './child.vue'; export default { components: { child }, data () { return { message: 'father message'; } } } </script> 复制代码
子组件vue模板child.vue:
<template> <div>{{msg}}</div> </template> <script> export default { props: { msg: { type: String, required: true } } } </script> 复制代码
子组件向父组件通信
父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件
父组件vue模板father.vue:
<template> <child @msgFunc="func"></child> </template> <script> import child from './child.vue'; export default { components: { child }, methods: { func (msg) { console.log(msg); } } } </script> 复制代码
子组件vue模板child.vue:
<template> <button @click="handleClick">点我</button> </template> <script> export default { props: { msg: { type: String, required: true } }, methods () { handleClick () { //........ this.$emit('msgFunc'); } } } </script> 复制代码
非父子,兄弟组件之间通信
可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递
Bus.js可以是这样:
import Vue from 'vue' export default new Vue() 复制代码
在需要通信的组件都引入Bus.js:
<template> <button @click="toBus">子组件传给兄弟组件</button> </template> <script> import Bus from '../common/js/bus.js' export default{ methods: { toBus () { Bus.$emit('on', '来自兄弟组件') } } } </script> 复制代码
另一个组件也import Bus.js 在钩子函数中监听on事件
import Bus from '../common/js/bus.js' export default { data() { return { message: '' } }, mounted() { Bus.$on('on', (msg) => { this.message = msg }) } } 复制代码
路由跳转方式
1,<router-link to='home'> router-link标签会渲染为<a>标签,咋填template中的跳转都是这种; 2,另一种是编程是导航 也就是通过js跳转 比如 router.push('/home') 复制代码
MVVM
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑 V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来 VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View 复制代码
computed和watch有什么区别?
computed:
1. computed是计算属性,也就是计算值,它更多用于计算值的场景 2. computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算 3. computed适用于计算比较消耗性能的计算场景 复制代码
watch:
1. 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作 2. 无缓存性,页面重新渲染时值不变化也会执行 复制代码
小结:
1. 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed 2. 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化 复制代码
给大家推荐一个实用面试题库
1、前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
【面试题】2023 中级前端面试题(下):https://developer.aliyun.com/article/1414184