初级前端面试题(2),字节跳动Web前端岗经典面试真题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去

原型和原型链的关系

instance.constructor.prototype = instance.proto

复制代码

原型和原型链的特点

JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变

当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的

就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象

组件化和模块化

组件化

为什么要组件化开发

有时候页面代码量太大,逻辑太多或者同一个功能组件在许多页面均有使用,维护起来相当复杂,这个时候,就需要组件化开发来进行功能拆分、组件封装,已达到组件通用性,增强代码可读性,维护成本也能大大降低

组件化开发的优点

很大程度上降低系统各个功能的耦合性,并且提高了功能内部的聚合性。这对前端工程化及降低代码的维护来说,是有很大的好处的,耦合性的降低,提高了系统的伸展性,降低了开发的复杂度,提升开发效率,降低开发成本

组件化开发的原则

  • 专一

  • 可配置性

  • 标准性

  • 复用性

  • 可维护性

模块化

为什么要模块化

早期的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

复制代码

子组件vue模板child.vue:

{{msg}}

复制代码

子组件向父组件通信

父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件

父组件vue模板father.vue:

<child @msgFunc=“func”>

复制代码

子组件vue模板child.vue:

<button @click=“handleClick”>点我

复制代码

非父子,兄弟组件之间通信

可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递

Bus.js可以是这样:

import Vue from ‘vue’

export default new Vue()

复制代码

在需要通信的组件都引入Bus.js:

<button @click=“toBus”>子组件传给兄弟组件

复制代码

另一个组件也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标签会渲染为标签,咋填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来观察这个数据变化

复制代码

key

key是为Vue中的vnode标记的唯一id,通过这个key,我们的diff操作可以 更准确、更快速

准确:

如果不加key,那么vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的bug

快速:

key的唯一性可以被Map数据结构充分利用

组件中的data为什么是函数?

为什么组件中的data必须是一个函数,然后return一个对象,而new Vue实例里,data可以直接是一个对象?

// data

data() {

return {

message: “子组件”,

childName:this.name

}

}

// new Vue

new Vue({

el: ‘#app’,

router,

template: ‘’,

components: {App}

})

复制代码

因为组件是用来复用的,JS里对象是引用关系,这样作用域没有隔离,而new Vue的实例,是不会被复用的,因此不存在引用对象问题

Class 与 Style 如何动态绑定?

Class 可以通过对象语法和数组语法进行动态绑定:

对象语法

data: {

isActive: true,

hasError: false

}

复制代码

数组语法

data: {

activeClass: ‘active’,

errorClass: ‘text-danger’

}

复制代码

Style 也可以通过对象语法和数组语法进行动态绑定:

对象语法

data: {

activeColor: ‘red’,

fontSize: 30

}

复制代码

数组语法

data: {

styleColor: {

color: ‘red’

},

styleSize:{

fontSize:‘23px’

}

}

复制代码

vue的单项数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改

有两种常见的试图改变一个 prop 的情形 :

这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用

在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:

props: [‘initialCounter’],

data: function () {

return {

counter: this.initialCounter

}

}

复制代码

这个 prop 以一种原始的值传入且需要进行转换

在这种情况下,最好使用这个 prop 的值来定义一个计算属性

props: [‘size’],

computed: {

normalizedSize: function () {

return this.size.trim().toLowerCase()

}

}

复制代码

keep-alive

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:

  • 一般结合路由和动态组件一起使用,用于缓存组件;

  • 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;

  • 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

v-model 的原理

vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;

  • checkbox 和 radio 使用 checked 属性和 change 事件;

  • select 字段将 value 作为 prop 并将 change 作为事件;

以 input 表单元素为例:

复制代码

相当于

复制代码

如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示:

父组件:

子组件:

{{value}}

props:{

value: String

},

methods: {

test1(){

this.$emit(‘input’, ‘小红’)

},

},

复制代码

nextTick()

在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的DOM

// 修改数据

vm.msg = ‘Hello’

// DOM 还未更新

Vue.nextTick(function () {

// DOM 更新

})

复制代码

vue插槽

个人觉得这篇文章写的还可以:www.cnblogs.com/chinabin199…

单个插槽

当子组件模板只有一个没有属性的插槽时,

父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,

并替换掉插槽标签本身

复制代码

命名插槽

solt元素可以用一个特殊的特性name来进一步配置如何分发内容。

多个插槽可以有不同的名字。 这样可以将父组件模板中 slot 位置,

和子组件 slot 元素产生关联,便于插槽内容对应传递

复制代码

作用域插槽

可以访问组件内部数据的可复用插槽(reusable slot)

在父级中,具有特殊特性 slot-scope 的 元素必须存在,

表示它是作用域插槽的模板。slot-scope 的值将被用作一个临时变量名,

此变量接收从子组件传递过来的 prop 对象

复制代码

vue-router有哪几种导航钩子

第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截

第二种:组件内的钩子

第三种:单独路由独享组件

vuex

vuex是什么?

vuex 就是一个仓库,仓库里放了很多对象。其中 state 就是数据源存放地,对应于一般 vue 对象里面的 data

state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖这相数据的组件也会发生更新

它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性

复制代码

Vuex有5种属性: 分别是 state、getter、mutation、action、module;

state

Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据

mutations

mutations定义的方法动态修改Vuex 的 store 中的状态或数据

getters

类似vue的计算属性,主要用来过滤一些数据

action

actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action

总结

vuex 一般用于中大型 web 单页应用中对应用的状态进行管理,对于一些组件间关系较为简单的小型应用,使用 vuex 的必要性不是很大,因为完全可以用组件 prop 属性或者事件来完成父子组件之间的通信,vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据

你有对 Vue 项目进行哪些优化?

代码层面的优化

v-if 和 v-show 区分使用场景

computed 和 watch 区分使用场景

v-for 遍历必须为 item 添加 key,且避免同时使用 v-if

长列表性能优化

事件的销毁

图片资源懒加载

路由懒加载

第三方插件的按需引入

优化无限列表性能

服务端渲染 SSR or 预渲染

复制代码

Webpack 层面的优化

Webpack 对图片进行压缩

减少 ES6 转为 ES5 的冗余代码

提取公共代码

模板预编译

提取组件的 CSS

优化 SourceMap

构建结果输出分析

Vue 项目的编译优化

复制代码

基础的 Web 技术的优化

开启 gzip 压缩

浏览器缓存

CDN 的使用

使用 Chrome Performance 查找性能瓶颈

复制代码

ES6


var、let、const之间的区别

var声明变量可以重复声明,而let不可以重复声明

var是不受限于块级的,而let是受限于块级

var会与window相映射(会挂一个属性),而let不与window相映射

var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错

const声明之后必须赋值,否则会报错

const定义不可变的量,改变了就会报错

const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错

解构赋值

数组解构

let [a, b, c] = [1, 2, 3] //a=1, b=2, c=3

let [d, [e], f] = [1, [2], 3] //嵌套数组解构 d=1, e=2, f=3

let [g, …h] = [1, 2, 3] //数组拆分 g=1, h=[2, 3]

let [i,j] = [1, 2, 3] //不连续解构 i=1, j=3

let [k,l] = [1, 2, 3] //不完全解构 k=1, l=2

复制代码

对象解构

let {a, b} = {a: ‘aaaa’, b: ‘bbbb’} //a=‘aaaa’ b=‘bbbb’

let obj = {d: ‘aaaa’, e: {f: ‘bbbb’}}

let {d, e:{f}} = obj //嵌套解构 d=‘aaaa’ f=‘bbbb’

let g;

(g = {g: ‘aaaa’}) //以声明变量解构 g=‘aaaa’

let [h, i, j, k] = ‘nice’ //字符串解构 h=‘n’ i=‘i’ j=‘c’ k=‘e’

复制代码

函数参数的定义

一般我们在定义函数的时候,如果函数有多个参数时,在es5语法中函数调用时参数必须一一对应,否则就会出现赋值错误的情况,来看一个例子:

function personInfo(name, age, address, gender) {

console.log(name, age, address, gender)

}

personInfo(‘william’, 18, ‘changsha’, ‘man’)

复制代码

上面这个例子在对用户信息的时候需要传递四个参数,且需要一一对应,这样就会极易出现参数顺序传错的情况,从而导致bug,接下来来看es6解构赋值是怎么解决这个问题的:

function personInfo({name, age, address, gender}) {

console.log(name, age, address, gender)

}

personInfo({gender: ‘man’, address: ‘changsha’, name: ‘william’, age: 18})

复制代码

这么写我们只知道要传声明参数就行来,不需要知道参数的顺序也没关系

交换变量的值

在es5中我们需要交换两个变量的值需要借助临时变量的帮助,来看一个例子:

var a=1, b=2, c

c = a

a = b

b = c

console.log(a, b)

复制代码

来看es6怎么实现:

let a=1, b=2;

[b, a] = [a, b]

console.log(a, b)

复制代码

是不是比es5的写法更加方便呢

函数默认参数

在日常开发中,经常会有这种情况:函数的参数需要默认值,如果没有默认值在使用的时候就会报错,来看es5中是怎么做的:

function saveInfo(name, age, address, gender) {

name = name || ‘william’

age = age || 18

address = address || ‘changsha’

gender = gender || ‘man’

console.log(name, age, address, gender)

}

saveInfo()

复制代码

在函数离 main先对参数做一个默认值赋值,然后再使用避免使用的过程中报错,再来看es6中的使用的方法:

function saveInfo({name= ‘william’, age= 18, address= ‘changsha’, gender= ‘man’} = {}) {

console.log(name, age, address, gender)

}

saveInfo()

复制代码

在函数定义的时候就定义了默认参数,这样就免了后面给参数赋值默认值的过程,是不是看起来简单多了

forEach、for in、for of三者区别

forEach更多的用来遍历数

for in 一般常用来遍历对象或json

for of数组对象都可以遍历,遍历对象需要通过和Object.keys()

for in循环出的是key,for of循环出的是value

使用箭头函数应注意什么?

1、用了箭头函数,this就不是指向window,而是父级(指向是可变的)

2、不能够使用arguments对象

3、不能用作构造函数,这就是说不能够使用new命令,否则会抛出一个错误

4、不可以使用yield命令,因此箭头函数不能用作 Generator 函数

Set、Map的区别

应用场景Set用于数据重组,Map用于数据储存

Set:

1,成员不能重复

2,只有键值没有键名,类似数组

3,可以遍历,方法有add, delete,has

Map:

1,本质上是健值对的集合,类似集合

2,可以遍历,可以跟各种数据格式转换

promise对象的用法,手写一个promise

promise是一个构造函数,下面是一个简单实例

var promise = new Promise((resolve,reject) => {

if (操作成功) {

resolve(value)

} else {

reject(error)

}

})

promise.then(function (value) {

// success

},function (value) {

// failure

})

复制代码

Ajax


如何创建一个ajax

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象

(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息

(3)设置响应HTTP请求状态变化的函数

(4)发送HTTP请求

(5)获取异步调用返回的数据

(6)使用JavaScript和DOM实现局部刷新

同步和异步的区别

同步:

浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作

异步:

浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容

ajax的优点和缺点

ajax的优点

1、无刷新更新数据(在不刷新整个页面的情况下维持与服务器通信)

2、异步与服务器通信(使用异步的方式与服务器通信,不打断用户的操作)

3、前端和后端负载均衡(将一些后端的工作交给前端,减少服务器与宽度的负担)

4、界面和应用相分离(ajax将界面和应用分离也就是数据与呈现相分离)

ajax的缺点

1、ajax不支持浏览器back按钮

2、安全问题 Aajax暴露了与服务器交互的细节

3、对搜索引擎的支持比较弱

4、破坏了Back与History后退按钮的正常行为等浏览器机制

get和post的区别

1、get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些 2、get相对post安全性低

3、get有缓存,post没有

4、get体积小,post可以无限大

5、get的url参数可见,post不可见

6、get只接受ASCII字符的参数数据类型,post没有限制

7、get请求参数会保留历史记录,post中参数不会保留

8、get会被浏览器主动catch,post不会,需要手动设置

9、get在浏览器回退时无害,post会再次提交请求

什么时候使用post?

post一般用于修改服务器上的资源,对所发送的信息没有限制。比如

1、无法使用缓存文件(更新服务器上的文件或数据库)

2、向服务器发送大量数据(POST 没有数据量限制)

3、发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

如何解决跨域问题

跨域的概念:协议、域名、端口都相同才同域,否则都是跨域

解决跨域问题:

1、使用JSONP(json+padding)把数据内填充起来

2、CORS方式(跨域资源共享),在后端上配置可跨域

3、服务器代理,通过服务器的文件能访问第三方资源

什么是Ajax和JSON,它们的优点和缺点

Ajax:

Ajax是异步JavaScript和XML,用于在Web页面中实现异步数据交互

Ajax优点:

异步请求响应快,用户体验好;页面无刷新、数据局部更新;按需取数据,减少了冗余请求和服务器的负担;

Ajax缺点:

异步回调问题、this指向问题、路由跳转back问题;对搜索引擎的支持比较弱,对于一些手机还不是很好的支持

JSON:

是一种轻量级的数据交换格式,看着像对象,本质是字符串

JSON优点:

轻量级、易于人的阅读和编写,便于js解析,支持复合数据类型

JSON缺点:

没有XML格式这么推广的深入人心和使用广泛, 没有XML那么通用性

Github


git常用的命令

从远程库克隆到本地:git clone 网站上的仓库地址

新增文件的命令:git add .

提交文件的命令:git commit –m或者git commit –a

查看工作区状况:git status –s

拉取合并远程分支的操作:git fetch/git merge或者git pull

查看提交记录命令:git reflog

webpack


webpack打包原理

webpack只是一个打包模块的机制,只是把依赖的模块转化成可以代表这些包的静态文件。webpack就是识别你的 入口文件。识别你的模块依赖,来打包你的代码。至于你的代码使用的是commonjs还是amd或者es6的import。webpack都会对其进行分析。来获取代码的依赖。webpack做的就是分析代码。转换代码,编译代码,输出代码。webpack本身是一个node的模块,所以webpack.config.js是以commonjs形式书写的(node中的模块化是commonjs规范的)

模块热更新

模块热更新是webpack的一个功能,他可以使代码修改过后不用刷新就可以更新,是高级版的自动刷新浏览器

devServer中通过hot属性可以控制模块的热替换

通过配置文件

const webpack = require(‘webpack’);

const path = require(‘path’);

let env = process.env.NODE_ENV == “development” ? “development” : “production”;

const config = {

mode: env,

devServer: {

hot:true

}

}

plugins: [

new webpack.HotModuleReplacementPlugin(), //热加载插件

],

module.exports = config;

复制代码

通过命令行

“scripts”: {

“test”: “echo “Error: no test specified” && exit 1”,

“start”: “NODE_ENV=development webpack-dev-server --config webpack.develop.config.js --hot”,

},

复制代码

如何提高webpack构建速度

1、通过externals配置来提取常用库

2、利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来

3、使用Happypack 实现多线程加速编译

要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下

4、使用Tree-shaking和Scope Hoisting来剔除多余代码 5、使用fast-sass-loader代替sass-loader 6、babel-loader开启缓存

babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率 可以加上cacheDirectory参数或使用 transform-runtime 插件试试

// webpack.config.js

use: [{

loader: ‘babel-loader’,

options: {

cacheDirectory: true

}]

// .bablerc

{

“presets”: [

“env”,

“react”

],

“plugins”: [“transform-runtime”]

}

复制代码

不需要打包编译的插件库换成全局"script"标签引入的方式

比如jQuery插件,react, react-dom等,代码量是很多的,打包起来可能会很耗时 可以直接用标签引入,然后在webpack配置里使用 expose-loader 或 externals 或 ProvidePlugin 提供给模块内部使用相应的变量

// @1

use: [{

loader: ‘expose-loader’,

options: ‘$’

}, {

loader: ‘expose-loader’,

options: ‘jQuery’

}]

// @2

externals: {

jquery: ‘jQuery’

},

// @3

new webpack.ProvidePlugin({

$: ‘jquery’,

jQuery: ‘jquery’,

‘window.jQuery’: ‘jquery’

}),

复制代码

8、优化构建时的搜索路径

在webpack打包时,会有各种各样的路径要去查询搜索,我们可以加上一些配置,让它搜索地更快 比如说,方便改成绝对路径的模块路径就改一下,以纯模块名来引入的可以加上一些目录路径 还可以善于用下resolve alias别名 这个字段来配置 还有exclude等的配置,避免多余查找的文件,比如使用babel别忘了剔除不需要遍历的

webpack的优点

专注于处理模块化的项目,能做到开箱即用,一步到位

可通过plugin扩展,完整好用又不失灵活

使用场景不局限于web开发

社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展

良好的开发体验

webpack的缺点

webpack的缺点是只能用于采用模块化开发的项目

微信小程序


文件主要目录及文件作用

  • component —————————————————— 组件文件夹

  • navBar —— 底部组件

  • navBar.js —— 底部组件的 JS 代码

  • navBar.json —— 底部组件的配置文件

  • navBar.wxml —— 底部组件的 HTML 代码

  • navBar.wxss —— 底部组件的 CSS 代码

  • pages ————————————————————— 页面文件夹

  • index —— 首页

  • index.js —— 首页的 JS 代码

  • index.json —— 首页的配置文件

  • index.wxml —— 首页的 HTML 代码

  • index.wxss —— 首页的 CSS 代码

  • public ————————————————————— 图片文件夹

  • utils —————————————————————— 工具文件夹

  • api.js —— 控制 API 的文件

  • md5.js —— 工具 - MD5 加密文件

  • timestamp.js —— 工具 - 时间戳文件

  • app.json ——————————————————— 设置全局的基础数据等

  • app.wxss ——————————————————— 公共样式,可通过 import 导入更多

  • project.config.json ———————— 项目配置文件

复制代码

微信小程序生命周期

onLoad():页面加载时触发。

onShow():页面显示/切入前台时触发。

onReady():页面初次渲染完成时触发。

onHide():页面隐藏/切入后台时触发。

onUnload():页面卸载时触发。

复制代码

如何封装数据请求

1,封装接口

项目/utils/api.js

// 将请求进行 Promise 封装

const fetch = ({url, data}) => {

// 打印接口请求的信息

console.log(【step 1】API 接口:${url});

console.log(“【step 2】data 传参:”);

console.log(data);

// 返回 Promise

return new Promise((resolve, reject) => {

wx.request({

url: getApp().globalData.api + url,

data: data,

success: res => {

// 成功时的处理

if (res.data.code == 0) {

console.log(“【step 3】请求成功:”);

console.log(res.data);

return resolve(res.data);

} else {

wx.showModal({

title: ‘请求失败’,

content: res.data.message,

showCancel: false

});

}

},

fail: err => {

// 失败时的处理

console.log(err);

return reject(err);

}

})

})

}

/**

  • code 换取 openId

  • @data {

  • jsCode - wx.login() 返回的 code

  • }

*/

export const wxLogin = data => {

return fetch({

url: “tbcUser/getWechatOpenId”,

data: data

})

}

复制代码

2,调用接口

项目/pages/login/login.js

import {

wxLogin,

} from ‘…/…/utils/api.js’

复制代码

3,使用接口

项目/pages/login/login.js

wxLogin({

jsCode: this.data.code

}).then(

res => {

console.log(“【step 4】返回成功处理:”);

console.log(res.data);

},

err => {

console.log(“【step 4】返回失败处理:”);

console.log(err);

}

)

复制代码

页面数据传递

通过 url 携带参数,在 onLoad() 中通过 options 获取 url 上的参数:

onLoad: function(options) {

console.log(options.userId);

}

复制代码

通过 Storage 来传递参数:

wx.setStorageSync(‘userId’, ‘jsliang’);

wx.getStorageSync(‘userId’);

复制代码

文末

逆水行舟不进则退,所以大家要有危机意识。

同样是干到35岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说35岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

为了帮助大家更好温习重点知识、更高效的准备面试,特别整理了《前端工程师核心知识笔记》电子稿文件。

内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

前端面试题汇总

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
如何封装数据请求

1,封装接口

项目/utils/api.js

// 将请求进行 Promise 封装

const fetch = ({url, data}) => {

// 打印接口请求的信息

console.log(【step 1】API 接口:${url});

console.log(“【step 2】data 传参:”);

console.log(data);

// 返回 Promise

return new Promise((resolve, reject) => {

wx.request({

url: getApp().globalData.api + url,

data: data,

success: res => {

// 成功时的处理

if (res.data.code == 0) {

console.log(“【step 3】请求成功:”);

console.log(res.data);

return resolve(res.data);

} else {

wx.showModal({

title: ‘请求失败’,

content: res.data.message,

showCancel: false

});

}

},

fail: err => {

// 失败时的处理

console.log(err);

return reject(err);

}

})

})

}

/**

  • code 换取 openId

  • @data {

  • jsCode - wx.login() 返回的 code

  • }

*/

export const wxLogin = data => {

return fetch({

url: “tbcUser/getWechatOpenId”,

data: data

})

}

复制代码

2,调用接口

项目/pages/login/login.js

import {

wxLogin,

} from ‘…/…/utils/api.js’

复制代码

3,使用接口

项目/pages/login/login.js

wxLogin({

jsCode: this.data.code

}).then(

res => {

console.log(“【step 4】返回成功处理:”);

console.log(res.data);

},

err => {

console.log(“【step 4】返回失败处理:”);

console.log(err);

}

)

复制代码

页面数据传递

通过 url 携带参数,在 onLoad() 中通过 options 获取 url 上的参数:

onLoad: function(options) {

console.log(options.userId);

}

复制代码

通过 Storage 来传递参数:

wx.setStorageSync(‘userId’, ‘jsliang’);

wx.getStorageSync(‘userId’);

复制代码

文末

逆水行舟不进则退,所以大家要有危机意识。

同样是干到35岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说35岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

为了帮助大家更好温习重点知识、更高效的准备面试,特别整理了《前端工程师核心知识笔记》电子稿文件。

内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

前端面试题汇总

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-wmzP6hFy-1713062658646)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值