ES6新特性列表
HTML面试常问
1.如何理解HTML语义化?
(荒野阶段)后台写HTML table标签-->(美工阶段)DIV+CSS-->(前端阶段)p acticle h1....
语义化,顾名思义,就是你写的HTML结构,是用相对应的有一定语义的英文字母(标签)表示的,标记的。简而言之,就是使用最合适的标签,比如段落就写 p 标签,标题就写 h1 标签,文章就写article标签,视频就写video标签,等等。
2.meta viewport 是做什么的?怎么写?
meta元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。换句话说:meta 标签主要用于描述页面的一些信息。
通过查阅文档,我们可以知道 meta 标签提供三个参数
name http-equiv content scheme viewport 是meta标签name属性的一种,指web页面上用户可见的区域,用于移动端页面设计。
比如:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
3.H5是什么?
以现在的定义,H5特指基于HTML5技术的交互网页应用(移动端页面),以商业用途为主。
4.你用过那些HTML5标签?
具体参考:HTML标签列表5
脚本:
<template>:通过 JavaScript 在运行时实例化内容的容器
章节:
<section>:定义文档中的一个章节
<nav>:定义只包含导航链接的章节
<article>:定义可以独立于内容其余部分的完整独立内容块
<aside>:定义和页面内容关联度较低的内容——如果被删除,剩下的内容仍然很合理
<header>:定义页面或章节的头部。它经常包含 logo、页面标题和导航性的目录
<footer>:定义页面或章节的尾部。它经常包含版权信息、法律信息链接和反馈建议用的地址
<main>:定义文档中主要或重要的内容
嵌入内容:
<video>:代表一段视频 及其视频文件和字幕,并提供了播放视频的用户界面
<video controls>
<source src="myVideo.mp4" type="video/mp4">
<source src="myVideo.webm" type="video/webm">
<p>Your browser doesn't support HTML5 video. Here is
a <a href="myVideo.mp4">link to the video</a> instead.</p>
</video>
<audio>:代表一段声音 ,或音频流
<audio controls="controls">
Your browser does not support the <code>audio</code> element.
<source src="foo.wav" type="audio/wav">
</audio>
<source>:为 <video> 或 <audio> 这类媒体元素指定媒体源
<canvas>:代表位图区域 ,可以通过脚本在它上面实时呈现图形,如图表、游戏绘图等
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 150, 100);
<svg>:定义一个嵌入式矢量图
<svg xmlns="http://www.w3.org/2000/svg"
width="150" height="100" viewBox="0 0 3 2">
//viewBox属性的值是一个包含4个参数的列表 min-x, min-y, width and height
<rect width="1" height="2" x="0" fill="#008d46" />
<rect width="1" height="2" x="1" fill="#ffffff" />
<rect width="1" height="2" x="2" fill="#d2232c" />
</svg>
<math>:定义一段数学公式
CSS面试常问
1.如何实现垂直居中?
1.块级元素内文字:height=line height
2.position=absolute + top:-子元素高度的一半/transform:translateY(-50%)
3.position=absolute + margin:auto
4.flex 布局——align-items:center
5.table自带
2.BFC是什么?
BFC:块级格式化上下文,是一个独立的布局环境,可以理解为一个容器,在这个容器中按照一定的规则进行物品摆放,并且不会影响其它环境的物品。创建BFC:
1.根元素或包含根元素的元素
2.浮动元素 float =left |right
3.position=absolute|fixed
4.display=inline-block|flex|inline-flex
5.overflow=hidden|auto
3.CSS选择器优先级。
1.越具体的越优先
2.同样优先级的写在后面的覆盖前面的
3.!important优先级最高
4.!important>内联样式> id> class> tag
4.如何清除浮动?
1.利用clear样式
2.在父级元素加个clearfix样式
.clearfix:after{
content:'';
display:block;
clear:both;
}
3.利用overflow清除浮动
5.什么是层叠上下文?
我们假定用户正面向(浏览器)视窗或网页,而 HTML 元素沿着其相对于用户的一条虚构的 z 轴排开,层叠上下文就是对这些 HTML 元素的一个三维构想。众 HTML 元素基于其元素属性按照优先级顺序占据这个空间。
原生JS
1.ES6语法知道那些?
举例:let const 箭头函数 Promise 展开操作符 默认参数 import export等详见上面的图片。
2.Promise、Promise.all、Promise.race分别怎么用?
function fn(){
return new Promise((resolve, reject)=>{
成功时调用 resolve(数据)
失败时调用 reject(错误)
})
}
fn().then(success, fail).then(success2, fail2)
Promise.all([promise1, promise2]).then(success1, fail1)
promise1和promise2都成功才会调用success1
Promise.race([promise1, promise2]).then(success1, fail1)
promise1和promise2只要有一个成功就会调用success1;
promise1和promise2只要有一个失败就会调用fail1;
总之,谁第一个成功或失败,就认为是race的成功或失败。
3.手写函数防抖和函数节流。
// 节流(一段时间执行一次之后,就不执行第二次)
function throttle(fn, delay){
let canUse = true
return function(){
if(canUse){
fn.apply(this, arguments)
canUse = false
setTimeout(()=>canUse = true, delay)
}
}
}
const throttled = throttle(()=>console.log('hi'))
throttled()
throttled()
// 防抖(一段时间会等,执行最后一次)
function debounce(fn, delay){
let timerId = null
return function(){
const context = this
if(timerId){window.clearTimeout(timerId)}
timerId = setTimeout(()=>{
fn.apply(context, arguments)
timerId = null
},delay)
}
}
const debounced = debounce(()=>console.log('hi'),3000)
debounced()
debounced()
4.手写AJAX。
var request = new XMLHttpRequest()
request.open('GET', '/a/b/c?name=ff', true);
request.onreadystatechange = function () {
if(request.readyState === 4 && request.status === 200) {
console.log(request.responseText);
}};
request.send();
5.理解代码里面的this。
可参考我的博客函数中的this
6.闭包和立即执行函数是什么?
闭包:我的理解就是闭包就是能够读取其他函数内部变量的函数,因为我们无法在外部读f1函数的局部变量a,所以我们构造了一个函数来获取这个变量,构造的这个函数就是闭包。
function f1(){
let a=100
function f2(){
return a
}
return f2()
}
立即执行函数:声明一个匿名函数,马上就调用这个函数,作用有:一是不必为函数命名,避免了污染全局变量; 二是内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
7.什么是JSONP,什么是CROS,什么是跨域?
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。
有时候我们需要实现跨域来完成我们想要的数据共享,最常用的两种方法是:跨域资源共享CORS和JSONP。
CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。
举个栗子:如果frank.com:9999运行的js想访问qq.com:8888里面的js访问的/friends.json,正常的AJAX是不能访问的,但是我们用CROS可以做到:我们可以在qq.com的响应头里写frank.com可以访问即可:
因为IE不支持CORS,为了兼容IE,所以才有了JSONP,JSONP的思路是:既然我们无法访问qq.com:8888/friends.json,但是我们可以引用qq.com:8888/friends.js啊,只需要让js包含数据内容即可。
8.async/await 怎么用,如何捕获异常?
await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。
如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
如果该值不是一个 Promise,await 会把该值转换为已正常处理的Promise,然后等待其处理结果。
async function f2() {
var y = await 20;
console.log(y); // 20
}
f2();
如果 Promise 处理异常,则异常值被抛出
async function f3() {
try {
var z = await Promise.reject(30);
} catch (e) {
console.log(e); // 30
}
}
f3();
9.如何实现深拷贝?
第一种:JSON 来深拷贝
var a = {...}
var b = JSON.parse( JSON.stringify(a) )
缺点:JSON 不支持函数、引用、undefined、RegExp、Date……
第二种:递归拷贝
function deepClone(obj) {
//判断传递的目标是否为对象或者数组,根据情况创建空对象或者数组
let result = typeof obj.splice === 'function' ? [] : {};
//判断条件为必须是object类型
if (obj && typeof obj === "object"){
//遍历对象
for (let key in obj) {
//判断遍历对象中的属性(key)是否object类型
if (obj[key] && typeof obj[key] === "object"){
//再次重新执行一遍,递归方式
result[key] = deepClone(obj[key])
}else{
//将属性(key)直接赋值给新对象或数组
result[key] = obj[key]
}
}
//返回result
return result
}
//返回obj
return obj
}
区别:
1.浅拷贝并不复制对象本身而是复制一个指针,新对象和旧对象都是在同一块内存地址
2.深拷贝则会复制整个对象,新对象与旧对象是两块内存地址
10.如何用正则实现 trim()?
function trim(string){
return string.replace(/^\s+|\s+$/g, '')
}
11.不用 class 如何实现继承?用 class 又如何实现?
function Animal(color){
this.color = color
}
Animal.prototype.move = function(){} // 动物可以动
function Dog(color, name){
Animal.call(this, color) // 或者 Animal.apply(this, arguments)
this.name = name
}
// 下面三行实现 Dog.prototype.__proto__ = Animal.prototype
function temp(){}
temp.prototype = Animal.prototype
Dog.prototype = new temp()
Dog.prototype.constuctor = Dog // 这行看不懂就算了,面试官也不问
Dog.prototype.say = function(){ console.log('汪')}
var dog = new Dog('黄色','阿黄')
用Class
class Animal{
constructor(color){
this.color = color
}
move(){}
}
class Dog extends Animal{
constructor(color, name){
super(color)
this.name = name
}
say(){}
}
12.如何实现数组去重
//用Set方法去重
const array = [1, 5, 2, 3, 4, 2, 3, 1, 3, 4];
function unique(x) {
return [...new Set(x)]; //...扩展运算符,将之逗号分开
}
unique(array); //[1,5,2,3,4]
//不用Set方法
const array = [1, 5, 2, 3, 4, 2, 3, 1, 3, 4];
let unique = (a) => {
let arr = [];
for (let i = 0; i < x.length; i++) {
if (arr.indexOf(a[i]) === -1) {
arr.push(a[i]);
}
}
return arr;
};
unique(array); //[1,5,2,3,4]
//使用arr.filter
const array = [1, 5, 2, 3, 4, 2, 3, 1, 3, 4];
function unique(arr) {
return arr.filter((item, index, array) => array.indexOf(item) === index);
}
unique(array); //[1,5,2,3,4]
DOM面试常问
1.事件委托
通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件。也就是:利用冒泡的原理,把事件加到父级上,触发执行效果。好处有:1.节约监听数量 2. 可以监听动态生成的元素
错误版(但是可能能过)
ul.addEventListener('click', function(e){
if(e.target.tagName.toLowerCase() === 'li'){
fn() // 执行某个函数
}
})
bug 在于,如果用户点击的是 li 里面的 span,就没法触发 fn,这显然不对。
高级版
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
思路是点击 span 后,递归遍历 span 的祖先元素看其中有没有 ul 里面的 li。
2.请简述 DOM 事件模型或 DOM 事件机制
捕获:当用户点击按钮,浏览器会从 window 从上向下遍历至用户点击的按钮,逐个触发事件处理函数。 冒泡:浏览器从用户点击的按钮从下往上遍历至 window,逐个触发事件处理函数。 W3C 事件模型/事件机制:对每个事件先捕获再冒泡
3.实现一个可拖动的div
//HTML
<div id="xxx"></div>
//CSS
div{
border: 1px solid red;
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
}
*{margin:0; padding: 0;}
//JS
var dragging = false
var position = null
xxx.addEventListener('mousedown',function(e){
dragging = true
position = [e.clientX, e.clientY]
})
document.addEventListener('mousemove', function(e){
if(dragging === false)
{return}
const x = e.clientX
const y = e.clientY
const deltaX = x - position[0]
const deltaY = y - position[1]
const left = parseInt(xxx.style.left || 0)
const top = parseInt(xxx.style.top || 0)
xxx.style.left = left + deltaX + 'px'
xxx.style.top = top + deltaY + 'px'
position = [x, y]
})
document.addEventListener('mouseup', function(e){
dragging = false
})
HTTP面试常问
1.HTTP 状态码知道哪些?分别什么意思?
HTTP协议状态码表示的意思主要分为五类,大体是:
- 1××:保留
- 2××:表示请求成功地接收
- 3××:为完成请求客户需进一步细化请求
- 4××:客户错误
- 5××:服务器错误
200 表示响应成功
206表示部分内容,服务器处理了部分get请求
301表示永久重定向,被请求的资源已永久移动到新位置
302表示临时重定向,请求的资源现在临时从不同的响应请求
400表示错误请求。
401表示未经授权。
403表示禁止访问。
404表示文件未找到。
500表示内部服务器错误。
502表示无效网关。
2.HTTP 缓存有哪几种?
缓存存分为两种:强缓存和协商缓存,根据响应的 header 内容来决定。
- 强缓存相关字段有 expires,cache-control。如果 cache-control 与 expires 同时存在的话, cache-control 的优先级高于 expires。
- 协商缓存相关字段有 Last-Modified/If-Modified-Since,Etag/If-None-Match
3.GET 和 POST 的区别
错解,但是能过面试
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被加入收藏栏,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
正解
- 就一个区别:语义——GET 用于获取资源,POST 用于提交资源
4.Cookie V.S. LocalStorage V.S. SessionStorage V.S. Session
-
Cookie V.S. LocalStorage Cookies和本地存储有不同的用途。Cookies主要用于读取服务器端,本地存储只能由客户端读取(设置cookie:response.setHeader('Set-Cookie','xxx'),读取:request.headers['cookie'])而 LocalStorage 不会发送 Cookie 一般最大 4k,LocalStorage 可以用 5Mb 甚至 10Mb(各浏览器不同)
-
LocalStorage V.S. SessionStorage LocalStorage 一般不会自动过期(除非用户手动清除),而 SessionStorage 在回话结束时过期(如关闭浏览器)
-
Cookie V.S. Session Cookie 存在浏览器的文件里,Session 存在服务器的文件里 Session 是基于 Cookie 实现的,具体做法就是把 SessionID 存在 Cookie 里
Vue常问面试题
1.什么是生命周期?什么是生命周期钩子?有哪些?
Vue实例从创建到销毁的过程叫生命周期,钩子函数则是Vue实例或组件在生命周期过程中各个阶段自执行的回调函数。有:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。
2.watch 和 computed 和 methods 区别是什么?
methods:方法 computed:计算属性 watch:侦听器
methods和computed相比conputed依赖值不变的时候可直接用缓存,methods每次都会执行。 computed和watch相比watch监听某个数据变化执行相应的函数,computed不能执行异步任务,watch可以。
3.v-show和v-if的区别。
v-show:元素总是会被渲染,只是基于CSS切换。 v-if:是真正的条件渲染,是完整的销毁和重新创建。 使用 频繁切换时用v-show,运行时较少改变时用v-if
4.Vue 如何实现组件间通信
1.父子组件:使用 v-on 通过事件通信 2.爷孙组件:使用两次 v-on 通过爷爷爸爸通信,爸爸儿子通信、爷孙通信或者用provide和eject 3.任意组件:使用 eventBus = new Vue() 来通信,eventBus.emit 是主要API 4.任意组件:使用 Vuex 通信
5.Vue 数据响应式怎么做到的?
Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
并且每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。 Vue 不能检测到对象属性的添加或删除,解决方法是手动调用 Vue.set 或者 this.$set
6.列表遍历时key作用?
key的特殊attribute主要用在Vue的虚拟DOM算法,可以让diff操作更准确更快速。 比如渲染一堆input框,中间删除一个就会产生问题,下面的input会被顶上来,vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留,从而产生一系列的bug。使用key时可以让key不存在的元素移除。
7.nextTick()怎么用?
在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的DOM
// 修改数据
vm.msg = 'Hello'
// DOM 还未更新
Vue.nextTick(function () {
// DOM 更新
})
8.Vuex 你怎么用的?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式;或者说就是一个仓库,仓库里放了很多对象。
Vuex有5种属性: 分别是 state、getter、mutation、action、module;
1.state 全局数据
2.getters 由state变化派生的数据
3.mutations 对state的直接修改
4.action action提交的是mutation,而不是直接变更状态,可以是异步操作
5.module
当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、getter、mutation、action
总结 1.vuex 一般用于中大型 web 单页应用中对应用的状态进行管理, 2.对于一些组件间关系较为简单的小型应用,使用 vuex的必要性不是很大,因为完全可以用组件prop属性或者事件来完成父子组件之间的通信 3.vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据
9.VueRouter 你怎么用的?
Vue Router 是 Vue.js 官方的路由管理器。
原理:
Hash模式:监听hash的change,决定渲染对应的模块
History模式,HTML5的API:pushState和replaceState这两个API可以改变URL的同时不发送请求,这样监听URL的变化来实现更新部分页面内容的操作。
常用 API:router-link/router-view/this.$router.push/this.$router.replace/this.$route.params
常用的两个路由守卫:router.beforeEach 和 router.afterEach
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。
在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。
判断是否登录,是否拿到对应的路由权限等等。
10.路由懒加载
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
const Foo = () => import('./Foo.vue')//import返回一个Promise
11.你有对 Vue 项目进行哪些优化?
- 不要在模板里面写过多表达式
- 循环调用子组件时添加key
- 频繁切换的使用v-show,不频繁切换的使用v-if
- 尽量少用float,可以用flex
- 按需加载,可以用require或者import()按需加载需要的组件
- 路由懒加载
12.Vue的全局属性有哪些
$ref / $data / $router / $route / $data / $el / $props / $root / $parent / $children / $slots ...
$route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数。
$router 是“路由实例”对象,即使用 new VueRouter创建的实例,包括了路由的跳转方法,钩子函数等。
13.v-if VS v-for
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
14.Vue.js的两个核心
数据驱动:ViewModel,保证数据和视图的一致性。
组件系统:应用类UI可以看作全部是由组件树构成的。
15.什么是异步组件?
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
16.异步请求适合在那个生命周期调用?
mounted, 因为这个时候组件可能需要涉及到对DOM的操作。
17.为什么Vue采用异步渲染?
因为如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染. 所以为了性能考虑。Vue会在本轮数据更新后,再去异步更新视图! 有点类似节流的原理。
React面试常问
1. 生命周期函数
挂载时:
cosntructor()
render()
componentDidMount()
更新时:
shouldComponentUpdate()//用于在没有必要更新 UI 的时候返回 false,以提高渲染性能
render()
componentDidUpdate()
卸载时:
componentWillUnmount()
错误处理:
conponentDidCatch()
2.受控组件 V.S. 非受控组件
受控组件 非受控组件 区别受控组件的状态由开发者维护,非受控组件的状态由组件自身维护(不受开发者控制)获取数据就是相当于操作DOM。
3.React 如何实现组件间通信
- 父子靠 props 传函数
- 爷孙可以穿两次 props
- 任意组件用 Redux(也可以自己写一个 eventBus)
4.列表渲染时为什么加key
dom diff用于识别原有dom,用于提升性能。
5.虚拟DOM是什么
虚拟 DOM 就是用来模拟 DOM 的一个对象,这个对象拥有一些重要属性,并且更新 UI 主要就是通过对比(DIFF)旧的虚拟 DOM 树 和新的虚拟 DOM 树的区别完成的。
6. Redux 是什么?
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 Action/Reducer/Store/单向数据流 常用 API:store.dispatch(action)/store.getState()
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
let store = createStore(counter);
store.subscribe(() =>
console.log(store.getState())
);
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1
7.React原理
babel把jsx变成React.createElement,用于把jsx变成一个包含属性和孩子的数据对象(虚拟DOM)。通过render方法把虚拟DOM渲染成真正DOM放在页面。当setState时重新执行render,执行DOM diff 。
8.如何实现组件懒加载
React.lazy(()=>import('xxx'))
9.React-Router
HashRouter/BrowserRouter
Link
Switch
Route
Webpack面试题常问
1.loader 和 plugin 的区别是什么?有哪些常见 loader 和 plugin,你用过哪些?
Loader直译为"加载器"。 Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
Plugin直译为"插件"。 Plugin可以扩展Webpack的功能。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
常用的loader: file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 image-loader:加载并且压缩图片文件 babel-loader:把 ES6 转换成 ES5 css-loader:加载 CSS,支持模块化、压缩、文件导入等特性 style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。 eslint-loader:通过 ESLint 检查 JavaScript 代码
常用的plugin: html-webpack-plugin:HTML文件生成插件; mini-css-extract-plugin :css提取插件; TerserWebpackPlugin:用于压缩js,更新,支持es6语法
2.如何提高构建速度?
- 优化 loader 配置,配置test 、 include 、 exclude
- terser-webpack-plugin,开启缓存和多进程压缩
- thread-loader 为每个loder开辟单独的进程
- cache-loader 给loader设置缓存
3.如何利用Webpack来优化前端性能
- tree shaking 移除dead-code,减小文件提及
- js、css压缩合并,图片压缩或者内联,html压缩
- 抽离公共的js或者css
- 模块懒加载
4. 打包文件大怎么解决
- 使用生产环境
- 压缩合并
- 抽离公共的文件
- 模块懒加载
补充
1.浏览器的渲染过程
- 解析HTML生成DOM树。
- 解析CSS生成CSSOM规则树。
- 将DOM树与CSSOM规则树合并在一起生成渲染树。
- 遍历渲染树开始布局,计算每个节点的位置大小信息。
- 将渲染树每个节点绘制到屏幕。
2.你是如何理解前端工程化的?
我个人理解主要是从模块化、组件化、规范化、自动化这四个方面来实现前端工程化的:
1.模块化:
简单来说,模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。就像是独立的功能和项目就比如淘宝它又购物、直播、登录、注册...
2.组件化:
把重复的代码提取出来合并成为一个个组件,组件最重要的就是重用(复用),位于框架最底层,其他功能都依赖于组件,可供不同功能使用,独立性强。
3.规范化:
比如目录结构的制定、代码的规范、接口的规范、命名的规范等,遵循一套规范可以让代码更容易维护,出问题的时候也方便快速定位
4.自动化:
任何简单机械的重复劳动都应该让机器去完成,比如自动化测试、自动化部署等