前端面试题(附答案)持续更新中……

发布时间:2023-05-24 12:30

前端面试笔记

前言

关于前端面试的题,这里整理了一些干货,经常被问到的一些问题,出现频率比较高的问题,如有不足之处,请大家指出,持续更新…(ps:一到三颗代表重要性,选择性了解,掌握,前端需要知道的知识)
\"在这里插入图片描述\"

一、HTML篇

1.语义话的目的是什么?

答:用正确的标签做正确的事。

提高代码的可读性,页面内容结构化,便于开发人员的代码编写,同时提高的用户体验;有利于SEO ,便于搜索引擎爬虫爬取有效信息。

2.HTML5新特征

  1. Canvas绘图以及SVG绘图。
  2. 拖放(Drag and drop)API
  3. 语义化标签(header、nav、footer、article、section)
  4. 音频、视频(audio、video)API
  5. 地理定位(Geolocation)
  6. 本地离线存储(localStorage),长期存储数据,关闭浏览器后不丢失。
  7. 会话储存(sessionStorage),数据在关闭浏览器后自动删除。
  8. 表单控件(calendar、date、time、email、url、search)
  9. 新技术如Web Worker、Web Socket。(关于Web Socket使用可以看这篇文章浅谈Web Socket。)

3.cookie与sessionStorage和localStorage的区别

  1. 保存方式
    cookie存放在客户的浏览器上。
    session都在客户端中保存,不参与服务器通讯。

  2. 生命周期
    cookie可设置失效时间
    localStorage除非手动清除否则永久保存
    sessionStorage关闭当前页面或浏览器后失效

  3. 存储的大小
    cookie 4kb左右
    session 5M

  4. 易用性
    cookie需自己封装
    session可以接受原生接口

因为cookie每次请求都会携带在http请求中,所以它的主要用来识别用户登录,localStorage可以用来跨页面传参,sessionStorage可以用来保留一些临时数据。

关于storage使用的方式可以查看storage传值

二、CSS篇

1.css有哪些基本的选择器,执行先后顺序?

类选择器(class)、标签选择器、ID选择器
!important>内联样式(非选择器)>ID选择器>类选择器>标签选择器>通配符选择器(*)

2.垂直居中DIV

请看这里前端CSS布局问题

3.两栏布局左边固定右边自适应

请看这里前端CSS布局问题

3.三栏布局左右固定中自适应

请看这里前端CSS布局问题

4.常用的块与行属性内标签有哪些?有什么特征

块标签:div、h1~h6、ul、li、table、p、br、form。
特征:独占一行,换行显示,可以设置宽高,可以嵌套块和行
行标签:span、a、img、textarea、select、option、input。
特征:只有在行内显示,内容撑开宽、高,不可以设置宽、高(img、input、textarea等除外)。

5.清除浮动

  1. 父级div定义overflow:hidden(如果父级元素有定位元素超出父级,超出部分会隐藏,)
  2. 给浮动元素父级增加标签(由于新增标签会造成不必要的渲染,不建议使用)
  3. 伪元素清除浮动:给浮动元素父级增加 .clearfix::after(content: ‘’; display: table; clear: both;)(不会新增标签,不会有其他影响,)

6.CSS3新特征

  1. 圆角(border-radius)
  2. 阴影(box-shadow)
  3. 文字特效(text-shadow)
  4. 线性渐变(gradient)
  5. 变换(transform)
  6. 更多的CSS选择器
  7. 更多背景设置(background)
  8. 色彩模式(rgba)
  9. 伪元素(::selection)
  10. 媒体查询(@media)
  11. 多栏布局(column)
  12. 图片边框(border-image)

7.介绍一下盒模型

答:

  1. 盒模型由内容(content)、内边距(padding)、边框(border)、外边距(margin)组成。
  2. 盒模型分为IE盒模型和W3C标准盒模型。
  3. W3C标准盒模型又叫content-box,元素宽度/高度由border+padding+content组成。
    (属性width,height只包含内容content,不包含border和padding)
  4. IE盒模型又叫border-box,元素宽度/高度由content组成。
    (属性width,height包含border和padding,指的是content+padding+border。)

PS:盒模型这个东西需要多理解。。。

8.CSS中有哪些长度单位?

  1. 绝对长度单位:px
  2. 百分比: %
  3. 相对父元素字体大小单位: em
  4. 相对于根元素字体大小的单位: rem
  5. 相对于视口*宽度的百分比(100vw即视窗宽度的100%): vw
  6. 相对于视口*高度的百分比(100vh即视窗高度的100%): vh

9.display:none和visibility:hidden的区别

display:none:隐藏元素,在文档布局中不在给它分配空间(从文档中移除),会引起回流(重排)。
visibility:hidden: 隐藏元素,但是在文档布局中仍保留原来的空间(还在文档中),不会引起回流(重绘)。

10. 用CSS 实现长宽为浏览器窗口一半的正方形

  1. 已知父元素宽高用%

                width: 50%;
                padding-top: 50%;
                background-color: red;
    
  • 用vw

                width: 50vw;
                height: 50vh;
                background-color: red;
    

11. 用CSS 实现高度为0.5像素的线条

这个可以用伪类来实现

       .line::before {
            display: block;
            content: "";
            height: 1px;
            left: -50%;
            position: absolute;
            background-color: #333333;
            width: 200%; //设置为插入元素的两倍宽高
            -webkit-transform: scale(0.5);
            transform: scale(0.5);
            box-sizing: border-box;
        }

12. 用CSS 实现三角形

向上

                width:0;
                height:0;   
                border-left:30px solid transparent;   
                border-right:30px solid transparent;   
                border-bottom:30px solid red;

13. 伪类和伪元素的区别

伪类
\"在这里插入图片描述\"
伪元素
\"在这里插入图片描述\"
区别

  • 伪类只能使用“”,伪元素既可以使用“:”,也可以使用“::”
  • 伪元素其实相当于伪造了一个元素,伪类没有伪造元素,例如first-child只是给子元素添加样式而已。(本质区别就是是否抽象创造了新元素

13. 重绘和重排是什么?如何避免?

重排:当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,所以重绘跳过了创建布局树和分层的阶段。

重排需要重新计算布局树,重绘不需要,重排必定发生重绘,但是涉及到重绘不一定要重排 。涉及到重排对性能的消耗更多一些。

触发重排的方法: 页面初始渲染、添加/删除可见的DOM元素、改变元素位置、改变元素尺寸、改变元素内容、改变元素字体大小、改变浏览器窗口尺寸、设置 style 属性的值等。
避免重排的方式:样式集中改变、使用 absolute 或 fixed 脱离文档流。

三、JS篇

1.ES6新特性?

  1. 新增块级作用域let定义变量和const定义常量
  2. 变量的解构赋值
  3. 模板字符串 (‘${}’)
  4. 默认参数(key=value)
  5. 箭头函数(=>)
  6. 扩展运算符(…)
  7. 模块(import/export)
  8. 类(class/extends)
  9. Promise
  10. Proxy
  11. Symbol
    了解关于es6的更多知识可以看阮一峰——ES6 入门教程

2.闭包的理解

理解:主要是为了设计私有的方法和变量。
优点:可以避免全局变量造成污染。
缺点:闭包会常驻内存,增加内存使用量,使用不当会造成内存泄漏。
特征:(1)函数嵌套函数。(2)在函数内部可以引用外部的参数和变量。(3)参数和变量不会以垃圾回收机制回收。

3.call()、apply()、bind()的区别

详情请看call()、apply()、bind()重新定义this的区别

4.原型,原型链

主要是还是实现继承与扩展对象。
每个函数对象都有一个 prototype 属性,这个属性就是函数的原型对象。
原型链是JavaScript实现继承的重要方式,原型链的形成是真正是靠__proto__ 而非prototype。

所有的引用类型(包括数组,对象,函数)都有隐性原型属性(proto), 值也是一个普通的对象。
所有的引用类型的 proto 属性值都指向构造函数的 prototype 属性值。
构造函数 new 出来一个对象,而每个对象都有一个 constructor 属性,该属性指向创建该实例的构造函数。
实例对象通过__proto__或者 object.getPrototype 的方法获取原型。
原型链其实就是有限的实例对象和原型之间组成有限链,就是用来实现共享属性和继承的。

详细可以看看这篇文章最详尽的 JS 原型与原型链终极详解

5.JS基本数据类型

  1. 基本类型
  • Number:数值,包括整型和浮点型。
  • String:字符型。
  • Undefined:未定义,声明变量时未赋值。
  • Null:定义为空或者不存在。
  • Boolean:布尔值,true or false。
  • Symbol:独一无二的值。
  1. 引用数据类型
  • Object:对象。

  • Array:数组。

  • Function:函数。

    注:**Object.prototype.toString.call()**适用于所有类型的判断检测

6.export和export default的区别

  • 均可导出常量、函数、文件、模块等。
  • 在一个文件或模块中,export、import可以有多个。export default仅有一个。
  • 通过export方式导出,在导入时要加{ },export default则不需要。

7.箭头函数和普通函数的区别

  • 语法更加简洁、清晰,=>()
  • 箭头函数是匿名函数,不能作为构造函数,不能使用new
  • 箭头函数不能使用arguments,而用reat参数…解决
  • 箭头函数没有自己的this,会捕获其所在的上下文的this值,并且不能通过call()和apply()来改变其this
  • 箭头函数没有原型

8.GET和POST的区别

表面区别

  • 后退/刷新:GET无害,POST数据会被重新提交。
  • 书签:GET产生的URL地址可以被收藏为书签,而POST不可以。
  • 数据:GET一般是用来获取数据,POST提交数据。
  • 数据类型:GET只允许ASCII字符,POST无限制。
  • 数据大小:GET大小有限制(一般来说1024字节),POST理论上来说没有大小限制。
  • 安全性:GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • 可见性:GET参数通过URL传递对所有人可见,POST数据不可见。
  • 历史保留:GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

9.forEach和map的区别

forEach没有返回值,map返回新的数组。
map创建新数组,forEach不修改原数组。

10.JS基本数据类型的比较

\"黄色表示ture\"

11.对象的继承

常见的:

  1. 原型链继承
  2. 借用构造函数继承
  3. 原型链+借用构造函数的组合继承(使用 call 或 applay 方法)
  4. ES6中class 的继承(class可以通过extends关键字实现继承)

12.简述一下你理解的面向对象

面向对象是基于万物皆对象这个哲学观点. 把一个对象抽象成类,具体上就是把一个对象的静态特征和动态特征抽象成属性和方法,也就是把一类事物的算法和数据结构封装在一个类之中,程序就是多个对象和互相之间的通信组成的。

面向对象具有封装性,继承性,多态性

封装:隐蔽了对象内部不需要暴露的细节,使得内部细节的变动跟外界脱离,只依靠接口进行通信.封装性降低了编程的复杂性。
继承:使得新建一个类变得容易,一个类从派生类那里获得其非私有的方法和公用属性的繁琐工作交给了编译器。
多态:继承和实现接口和运行时的类型绑定机制所产生的多态,使得不同的类所产生的对象能够对相同的消息作出不同的反应,极大地提高了代码的通用性.。

13. == 和 ===的区别

相同点:都是判定两个是否相等
不同点:== 只比较不比较类型,而 ===会判断类型

14. 数组有哪些方法

详细可以看数组一些常用的方法

15. 普通的数组去重(笔试一般都会有)

在不涉及去重对象、NaN等情况下。

  1. IndexOf()
  2. 双重for循环
  3. es6的 […new Set()]
  4. filter()
  5. sort()
    面试随便写一两种就行、项目直接用new Set()(方便)

注 :如果有多维数组如 [1,[2],[3,[2,3,4,5]] ] 先扁平化再去重,
用**Array.flat(Infinity)**实现扁平化。

16. Promise

含义:异步编程的一种解决方案,用来解决回调地狱。
三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败) (Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。)

resolved函数作用:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)。
reject函数的作用:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
then: Promise 实例添加状态改变时的回调函数。可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。

缺点:无法取消Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

更多详情请看Promise 对象

17.JS中new操作符有什么用?

  • 创建临时对象,并将this指向临时对象
  • 将构造函数的原型属性方法挂载到新对象的__proto__(原型指针)上
  • return 临时对象

18.JS获取HTML DOM元素的方法

  • 通过ID获取(getElementById)
  • 通过name属性(getElementsByName)
  • 通过标签名(getElementsByTagName)
  • 通过类名(getElementsByClassName)
  • 获取html的方法(document.documentElement)
  • 获取body的方法(document.body)
  • 通过选择器获取一个元素(querySelector)
  • 通过选择器获取一组元素(querySelectorAll)
    用法以及防坑可看JS获取HTML DOM元素的方法

19.事件捕获和事件冒泡

  • 事件捕获和事件冒泡主要解决了页面事件流的问题。页面的事件流经过了三个阶段,分别是事件捕获、目标阶段和事件冒泡阶段。
  • 事件捕获是由外向内;而事件冒泡则是由内向外。
  • event.stopPropagation() 可以阻止事件流的进一步传播。
  • 采用事件代理的方式,能够节省内存消耗,对于动态改变子元素的时候,也非常有利,避免了很多麻烦的步骤,比如重新绑定事件。(把子元素的事件委托给父元素来处理)

20.虚拟dom

定义:虚拟DOM就是普通的js对象。用来描述真实dom结构的js对象,因为它不是真实的dom,所以才叫做虚拟dom。
作用:虚拟dom可以很好地跟踪当前dom状态,因为它会根据当前数据生成一个描述当前dom结构的虚拟dom,然后数据发生变化时,有生成一个新的虚拟dom,而两个虚拟dom恰好保存了变化前后的状态。然后通过diff算法,计算出当前两个虚拟dom之间的差异,得出一个更好的替换方案。

21.排序方式

  1. 冒泡排序:比较所有相邻元素,如果第一个比第二个大,则交换它们。
  2. 选择排序:找到数组中的最小值,选中它并将其放置在第一位。
  3. 插入排序:从第二个数开始往前比,比它大就往后排。
  4. 归并排序:把数组劈成两半,再递归地对数组进行“分”操作,直到分成一个个单独的数。
  5. 快速排序:从数组中任意选择一个基准,所有比基准小的元素放到基准前面,比基准大的元素放到基准的后面。

22.数组操作方法会改变原数组

会改变:push(),pop(),shift(),unshift() ,splice(),sort(),reverse()。
不变:concat(),split(),slice()。

23.JS有几种方法判断变量的类型?

  1. typeof
    判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object’。
  2. instanceof
    区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。
  3. constructor
    检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
  4. Object.prototype.toString.call()
    适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。(举例:字符串返回的是[object String])

instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,找到返回true,未找到返回false。
Object.prototype.toString.call原理:Object.prototype.toString 表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果

24.如何判断一个对象是否存在?

直接!XXX 这样会报错,因为没有定义
\"在这里插入图片描述\"
建议使用typeof运算符,判断XXX是否有定义。
\"在这里插入图片描述\"

三、计算机网络与其他知识篇

1.HTTP与HTTPS

HTTP:客户端与服务器之间数据传输的格式规范,表示“超文本传输协议”。
HTTPS:在HTTP与TCP之间添加的安全协议层。
默认端口号:HTTP:80,HTTPS:443。
传输方式:http是明文传输,https则是具有安全性的ssl加密传输协议。
连接方式:http的是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

2.TCP与UDP的区别

  1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
  2. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
  3. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  4. TCP首部开销20字节;UDP的首部开销小,只有8个字节。
  5. TCP提供可靠的服务。UDP适用于一次只传少量数据、对可靠要求不高的环境。

3.HTTP常见的状态码

HTTP常见的状态码

4.如何解决跨域

什么是跨域?
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
常见的:
1、JSONP跨域
原理:利用script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript。
2、跨域资源共享(CORS)
目前最常用的一种解决办法,通过设置后端允许跨域实现。
3、nginx反向代理
跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。
4、WebSocket协议跨域
5、proxy
前端配置一个代理服务器(proxy)代替浏览器去发送请求:因为服务器与服务器之间是可以通信的不受同源策略的影响。
详细可看九种常见的前端跨域解决办法

5.网页从输入url到页面加载发生了什么

  1. DNS解析
  2. TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析并渲染页面————>1.解析文档构建dom树。2.构建渲染树。3.布局与绘制渲染树。
  6. 连接结束

6.HTTP 传输过程

含义:从建立连接到断开连接一共七个步骤,就是三次招手四次挥手

  1. TCP 建立连接
  2. 浏览器发送请求命令
  3. 浏览器发送请求头
  4. 服务器应答
  5. 服务器回应信息
  6. 服务器发送数据
  7. 断开TCP连接

7.浏览器如何渲染页面的?

  1. 浏览器解析html源码,将HTML转换成dom树,
  2. 将CSS样式转换成stylesheet(CSS规则树),
  3. 浏览器会将CSS规则树附着在DOM树上,并结合两者生成渲染树(Render Tree)
  4. 生成布局(flow),浏览器通过解析计算出每一个渲染树节点的位置和大小,在屏幕上画出渲染树的所有节点
  5. 合成绘制生成页面。

8.对MVC和MVVM的理解

M:model(数据模型),V:view(视图),C:controller(逻辑处理),VM:(连接model和view)
MVC:单向通信。必须通过controller来承上启下。
MVVM:数据双向绑定,数据改变视图,视图改变数据。

9.深拷贝,浅拷贝

浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。

总而言之,浅拷贝改动拷贝的数组原数组也会变(慎用!项目中很多地方共用的数组都会变)。深拷贝修改新数组不会改到原数组。
实现方法
浅拷贝

  1. Object.assign()

  2. 函数库lodash的 _.clone 方法

  3. es6的展开运算符

  4. Array.prototype.concat()

  5. Array.prototype.slice()

            let arr=[{name:"uzi"}]
    
    1.         let arr1= Object.assign({}, arr);   arr1[0].name="xiaoming"
      
    2.         let arr2= _.clone(arr);              arr2[0].name="mlxg"
      
    3.         let arr3= [...arr]                   arr3[0].name="xiaohu"
      
    4.         let arr4 = arr.concat()              arr4[0].name="zitai"
      
    5.         let arr5 = arr.slice();              arr5[0].name="clearLove"
             console.log(arr[0].name==arr[1].name==arr[2].name==……);
             //true  arr[0].name="clearLove"
      

深拷贝

  1. JSON.parse(JSON.stringify())

  2. 函数库lodash的 _.cloneDeep 方法

  3. **jQuery.extend()**方法

  4. 手写递归方法(转)

    var $ = require(‘jquery’);
    let arr=[{name:“theShy”,age:“21”}]

    1.         let arr1= JSON.parse(JSON.stringify(arr));   arr1[0].name="rookie"
      
    2.         let arr2= _.cloneDeep(arr);                  arr2[0].name="ning"
      
    3.         let arr3= $.extend(true, {}, arr);           arr3[0].name="baolan"
              console.log(arr[0].name==arr[1].name==arr[2].name==……);
             //fales arr1[0].name="rookie" arr2[0].name="ning"
      

10.防抖与节流

防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
应用场景:
提交按钮用户注册时候的手机号验证邮箱验证

节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
应用场景:
window对象的resize、scroll事件
拖拽时候的mousemove
射击游戏中的mousedown、keydown事件
文字输入、自动完成的keyup事件

vue中使用详情可以看vue中使用防抖和节流

11.性能优化

举例:

  1. 减少http请求次数
  2. 减少DNS查找
  3. 避免重定向
  4. 使用Ajax缓存
  5. 少用全局变量、减少DOM操作的使用
  6. 优化图片大小,通过CSS Sprites(精灵图)优化图片,
  7. 将css放在顶部,将js放在底部

12.webpack是怎么打包的,babel又是什么

Webpack:把所有依赖打包成一个 bundle.js文件,通过代码分割成单元片段并按需加载。Webpack是以公共JS的形式来书写脚本的,但对AMD/CMD的支持也很全面,方便旧项目进行代码迁移。
把项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。

babel将es6、es7、es8等语法转换成浏览器可识别的es5或es3语法。

13.git 和 svn的区别

SVN集中式版本控制系统,版本库是集中放在中央服务器的,首先要从中央服务器哪里得到最新的版本,干完活后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作(如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了)

Git分布式版本控制系统,没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,只需把各自的修改推送给对方,就可以互相看到对方的修改了。

14.webSocket

webSocket:可以让服务器主动向客户端发送消息,适合开发聊天室,多人游戏等协作应用。

WebSocket协议是基于TCP的一种新的网络协议。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

15.require和import区别

  • 调用时间
    require运行时调用,理论上可以运用在代码任何地,甚至不需要赋值给某个变量之后再使用。
    lmport是编译时候调用,必须放在文件开头,而且使用格式也是确定的。
  • 遵循规范
    require 是 AMD规范引入方式
    import是es6的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法
  • 本质
    require是赋值过程,其实require 的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量。
    import是解构过程。

通过require 引入基础数据类型时,属于复制该变量。
通过require 引入复杂数据类型时,数据浅拷贝该对象。
出现模块之间的循环引用时,会输出已经执行的模块,而未执行的模块不输出(比较复杂)。CommonJS模块默认export的是一个对象,即使导出的是基础数据类型。

ES6 模块语法是 JavaScript 模块的标准写法,坚持使用这种写法,取代 Node.js 的 CommonJS 语法。
使用import取代require()。

// CommonJS 的写法
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// ES6 的写法
import { func1, func2 } from 'moduleA';

使用export取代module.exports。

// commonJS 的写法
var React = require('react');
var Breadcrumbs = React.createClass({
  render() {
    return <nav />;
  }
});
module.exports = Breadcrumbs;

// ES6 的写法
import React from 'react';
class Breadcrumbs extends React.Component {
  render() {
    return <nav />;
  }
};
export default Breadcrumbs;

16.事件循环(Event Loop)

原因:JavaScript是单线程,所有任务需要排队,前一个任务结束,才会执行后一个任务。

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务:不进入主线程、而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

同步和异步任务分别进入不同的执行环境, 先执行同步任务,把异步任务放入循环队列当中挂起,等待同步任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,再执行宏观任务。一直这样循环,反复执行。

微任务:Promise.then、catch、finally、async/await。
宏任务:整体代码 Script、UI 渲染、setTimeout、setInterval、Dom事件、ajax事件。

详情可看JavaScript 运行机制详解:再谈Event Loop

17.什么是单页面应用(SPA)

一个系统只加载一次资源,之后的操作交互、数据交互是通过路由、ajax来进行,页面并没有刷新。
在一个页面上集成多种功能,甚至整个系统就只有一个页面,所有的业务功能都是它的子模块,通过特定的方式挂接到主界面上。
优点

  • 前后端分离
  • 良好的交互体验——用户不用刷新页面,页面显示流畅
  • 减轻服务器压力——服务器只出数据
  • 共用一套后端代码——多个客户端可共用一套后端代码
  • 加载速度快,内容的改变不需要重新加载整个页面,对服务器压力小

缺点

  • SEO难度高——数据渲染在前端进行
  • 页面初次加载比较慢,页面复杂提高很多

多页面:一个应用多个页面,页面跳转时整个页面都刷新,每次都请求一个新的页面
有点:SEO效果好
缺点:页面切换慢,每次切换页面需要选择性的重新加载公共资源

详情可以参考构建单页Web应用

18.什么叫优雅降级和渐进增强?

渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。

在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容。向下兼容指的是高版本支持低版本的或者说后期开发的版本支持和兼容早期开发的版本,向上兼容的很少。大多数软件都是向下兼容的。

二者区别:
1、优雅降级和渐进增强只是看待同种事物的两种观点。
2、优雅降级观点认为应该针对那些最高级、最完善的浏览器来设计网站。
3、渐进增强观点则认为应关注于内容本身。

四、VUE篇

1.数据双向绑定原理

答:通过数据劫持结合发布—订阅模式,通过Object.defineProperty()为各个属性定义get、set方法,在数据发生改变时给订阅者发布消息,触发相应的事件回调。

2. vue生命周期

概念:从创建、初始化数据、编译模板、挂载DOM、渲染-更新-渲染、卸载等一系列过程,称为为Vue 实例的生命周期。

vue2.0

  • beforeCreate:创建前。此时,组件实例刚刚创建,还未进行数据观测和事件配置,拿不到任何数据。
  • created:创建完成。vue 实例已经完成了数据观测,属性和方法的计算(比如props、methods、data、computed和watch此时已经拿得到),未挂载到DOM,不能访问到el属性,el属性,ref属性内容为空数组常用于简单的ajax请求,页面的初始化。
  • beforeMount:挂载前。挂在开始之前被调用,相关的render函数首次被调用(虚拟DOM)。编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂在html到页面上
  • mounted:挂载完成。也就是模板中的HTML渲染到HTML页面中,此时可以通过DOM API获取到DOM节点,$ref属性可以访问常用于获取VNode信息和操作,ajax请求,mounted只会执行一次。
  • beforeUpdate:在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,不会触发附加地重渲染过程。
  • updated:更新后。在由于数据更改导致地虚拟DOM重新渲染和打补丁之后调用,
  • beforeDestroy;销毁前。在实例销毁之前调用,实例仍然完全可用。(一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件)
  • destroyed:销毁后。在实例销毁之后调用,调用后,vue实列指示的所有东西都会解绑,所有的事件监听器会被移除。
    其他:
    activated:在keep-alive组件激活时调用
    deactivated:在keep-alive组件停用时调用
    详情可看vue2.0官网生命周期钩子

vue3.0

  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted

\"请添加图片描述\"
详情可看vue3.0官网生命周期钩子

3.组件之间如何传值

一、Vue父子 组件之间传值

  • 子组件通过props来接受数据和通过$emit来触发父组件的自定义事件;

二、兄弟组件之间的传值

  • 建一个公共组件bus.js.。传递方通过事件触发bus.$emit。接收方通过在mounted(){}生命周期里触发bus.$on

三、可以通过VUEX 来跨组件传参。

四、父孙传值 $attrs(向下)$listeners(向上)

五、 祖先和子孙传值provide/inject

六、获取父组件实例this.$parent
详情可看vue之组件的传参方式

4.路由之间如何传参

  • 通过router-link路由导航跳转传递

    <router-link to=/a/${id}>routerlink传参

  • 跳转时使用push方法拼接携带参数。

    this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …ath: `/getlist/{id}`,
    })

  • 通过路由属性中的name来确定匹配的路由,通过params来传递参数。

    this.$router.push({
    name: ‘Getlist’,
    params: {
    id: id
    }
    })

  • 使用path来匹配路由,然后通过query来传递参数。

    this.$router.push({
    path: ‘/getlist’,
    query: {
    id: id
    }
    })

注意:query有点像ajax中的get请求,而paramspost请求。

params在地址栏中不显示参数,刷新页面,参数丢失,
其余方法在地址栏中显示传递的参数,刷新页面,参数不丢失。

详情请看Vue-router之简单的路由传参三种方法

5.谈一谈VUEX

原理:Vuex是专门为vue.js应用程序设计的状态管理工具。
构成:

  • state:vuex的基本数据,用来存储变量,存放的数据是响应式的。
  • mutations:提交更改数据,同步更新状态。
  • actions:提交mutations,可异步操作。
  • getters:是store的计算属性。
  • modules:模块,每个模块里面有四个属性。
    关于VUEX如何使用可以看VUE的传值问题

6.如何解决vuex页面刷新数据丢失问题?

原因:因为vuex里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,vuex里面的数据就会被清空。
解决方法:将vuex中的数据直接保存到浏览器缓存中。(一般是用sessionStorage)

7.computed和watch的区别?

computed值有缓存、触发条件是依赖值发生更改、 watch无缓存支持异步、监听数据变化

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 更多的是观察的作用,支持异步,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

computed应用场景:需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
watch应用场景:需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

详情请看Vue的计算属性与methods、watch的区别

8.如何封装axios?

这个根据自己项目实际情况来说,这篇文章写的不错可以看看Vue的axios的简单封装

9.Route和router的区别

  • route:是路由信息对象,包括“path,parms,hash,name“等路由信息参数。
  • Router:是路由实例对象,包括了路由跳转方法,钩子函数等。

10.v-show和v-if的区别

  • v-if:组件的销毁和重建,更适合带有权限的操作,切换开大。如果开始条件为false则什么都不做,只有为true才会编译。
  • v-show:css切换,隐藏显示更适合频繁切换。在任何情况下都会被编译,然后被缓存,而且dom元素会被保留。

11.vue中数据变了但是视图不跟新怎么解决?

原因:

  • 数组数据变动:使用某些方法操作数组,变动数据时,有些方法无法被vue监测。
  • Vue 不能检测到对象属性的添加或删除。
  • 异步更新队列:数据第一次的获取到了,也渲染了,但是第二次之后数据只有在再一次渲染页面的时候更新,并不能实时更新。

12.vue中data为什么是函数而不是对象?

官网中有这么一段介绍,详情可以看组件的复用
\"在这里插入图片描述\"
意思就是,在Vue中组件是可以被复用的,而当data是一个函数的时候,每一个实例的data都是独立的,不会相互影响了。

13.vue中父子组件传值,父组件异步请求,子组件不能实时更新怎么解决?(vue中数据不能实时更新怎么解决?)

首先了解父子组件生命周期执行顺序 ==>
加载渲染数据过程
父组件 beforeCreate -->
父组件 created -->
父组件 beforeMount -->
子组件 beforeCreate -->
子组件 created -->
子组件 beforeMount -->
子组件 mounted -->
父组件 mounted -->
原因:因为生命周期只会执行一次,数据是要等到异步请求以后才能拿到,那么子组件的mounted钩子执行的时候,还没有拿到父组件传递过来的数据,但是又必须要打印出来结果,那这样的话,就只能去打印props中的默认值空字符串了,所以打印的结果是一个空字符串。
解决办法:

  1. 使用v-if控制组件渲染的时机
    初始还没拿到后端接口的异步数据的时候,不让组件渲染,等拿到的时候再去渲染组件。使用v-if="变量"去控制,初始让这个变量为false,这样的话,子组件就不会去渲染,等拿到数据的时候,再让这个变量变成true,
    举例:

    data() {
    return {
    isTrue:false // 初始为false
    };
    },
    monted(){
    this.$post.a.b.c.getData(res=>{
    if(res.result){
    this.isTrue = true
    }
    })
    }

  2. 使用watch监听数据的变化
    举例:

    props: {
    tableData: {
    type: Array,
    default: [],
    },
    },
    watch: {
    tableData(val){
    console.log(val)
    }
    },

  3. 使用VueX

14.父子组件传参emit如何传多个参数?

子组件:

submit(){
	this.$emit('g',1,2,3,4,5)
}

父组件

g(val1,val2,val3,val4,val5) {
	console.log(val1,val2,val3,val4,val5)
}

15.Vue 路由跳转方式

  • router-link 标签跳转
  • this.$router.push()
  • this.$router.replace()
  • this.$router.go(n):(0:当前页,-1上一页,+1下一页,n代表整数)

16.条件渲染v-if 与 v-for 优先级

\"在这里插入图片描述\"
列表渲染指南

17.Vue 中 $nextTick 作用与原理?

异步渲染、获取DOM、Promise等。

Vue 在更新 DOM 时是异步执行的,在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取DOM,获取的仍然是未修改的DOM。 $nextTick的作用是:该方法中的代码会在当前渲染完成后执行,就解决了异步渲染获取不到更新后DOM的问题了。 n e x t T i c k 的 原 理 : nextTick的原理: nextTick的原理:nextTick本质是返回一个Promise 。

应用场景:在created()里面想要获取操作Dom,把操作DOM的方法放在$nextTick中

官网中是这么说的
\"在这里插入图片描述\"

18.Vue 中 for循环为什么加 key?

为了性能优化, 因为vue是虚拟DOM,更新DOM时用diff算法对节点进行一一比对,比如有很多li元素,要在某个位置插入一个li元素,但没有给li上加key,那么在进行运算的时候,就会将所有li元素重新渲染一遍,但是如果有key,那么它就会按照key一一比对li元素,只需要创建新的li元素,插入即可,不需要对其他元素进行修改和重新渲染。
key也不能是li元素的index,因为假设我们给数组前插入一个新元素,它的下标是0,那么和原来的第一个元素重复了,整个数组的key都发生了改变,这样就跟没有key的情况一样了。

五、REACT篇

1.React的生命周期(版本17.0.2)

概念:每个组件都包含 “生命周期方法”,你可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。
挂载

  • constructor():在 React 组件挂载之前,会调用它的构造函数。(注:如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。)
  • render(): class 组件中唯一必须实现的方法。
  • componentDidMount():在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。

更新

  • render(): class 组件中唯一必须实现的方法。
  • componentDidUpdate():在更新后会被立即调用。首次渲染不会执行此方法。

卸载

  • componentWillUnmount():在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

具体可用一张图来表示
\"在这里插入图片描述\"

详情可看官网组件的生命周期

2.React如何获取组件对应的DOM元素?

  • ref:通过当前class组件实例的一些特定属性来直接获取子节点实例。
    注意:不能在函数组件上使用 ref 属性,因为他们没有实例。
  • findDOMNode():findDOMNode 是一个访问底层 DOM 节点的应急方案(escape hatch)。
    注意:在大多数情况下,不推荐使用该方法,因为它会破坏组件的抽象结构。严格模式下该方法已弃用。findDOMNode 不能用于函数组件。
    详情请看官网:ReactDOM

3.React中可以在render访问refs吗?为什么?

答:不能,因为在render阶段refs还未生成。DOM 的读取在 pre-commit 阶段,DOM的使用在 commit 阶段。
\"在这里插入图片描述\"

4.React中什么是受控组件和非控组件?

渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

受控组件更新state的流程:

  • 可以通过初始state中设置表单的默认值

  • 每当表单的值发生变化时,调用onChange事件处理器

  • 事件处理器通过事件对象e拿到改变后的状态,并更新组件的state

  • 一旦通过setState方法更新state,就会触发视图的重新渲染,完成表单组件的更新

对于受控组件来说,输入的值始终由 React 的 state 驱动。你也可以将 value 传递给其他 UI 元素,或者通过其他事件处理函数重置,但这意味着你需要编写更多的代码。
详情看官网受控组件

非受控组件
如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就可以称为非受控组件。在非受控组件中,可以使用一个ref来从DOM获得表单值。而不是为每个状态更新编写一个事件处理程序。

官网解释:要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。

因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。
官网非受控组件

总结: 页面中所有输入类的DOM如果是现用现取的称为非受控组件,而通过setState将输入的值维护到了state中,需要时再从state中取出,这里的数据就受到了state的控制,称为受控组件

5.谈一谈React的状态提升?

官网是这么解释的:

多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

简单来说就是:将多个组件需要共享的状态提升到它们最近的父组件上,在父组件上改变这个状态然后通过props分发给子组件。对子组件操作,子组件不改变自己的状态。
可看官网的温度计数器例子

6.为什么要使用虚拟DOM?(什么是 Virtual DOM?)

Virtual DOM算法
用一张图片来表示
\"在这里插入图片描述\"
虚拟DOM
那就是虚拟DOM概念出现的地方,并且其性能要比真实DOM好得多。虚拟DOM只是DOM的虚拟表示。每当我们的应用程序状态更改时,虚拟DOM就会更新,而不是真实DOM。

React如何使用虚拟DOM

在React中,每个UI块都是一个组件,每个组件都有一个状态。React遵循可观察的模式,并监听状态变化。当组件的状态改变时,React更新虚拟DOM树。虚拟DOM更新后,React然后将虚拟DOM的当前版本与虚拟DOM的先前版本进行比较。此过程称为“差异化”。

一旦React知道哪些虚拟DOM对象已更改,然后React就会在真实DOM中仅 更新那些对象。与直接操作真实DOM相比,这使性能好得多。

原因:对于局部的小视图的更新,重新构造整棵 DOM没问题;但是对于大型视图,如全局应用状态变更的时候,需要更新页面较多局部视图的时候,这样的做法不可取。 Virtual DOM只是加了一些特别的步骤来避免了整棵 DOM 树变更。

简而言之就是:

  • 频繁的DOM操作昂贵且性能沉重。
  • 虚拟DOM是真实DOM的虚拟表示。
  • React使用虚拟DOM来增强其性能。
  • JS 和 DOM 之间的缓存。

更深入可看深度剖析:如何实现一个 Virtual DOM 算法

六、其它篇

1.开发中遇到的bug?

项目中或者地图中遇到引入如图片不显示。

解决办法:使用require动态引入图片。
详细可看设置content加载不出图标

合并多个对象并去重

原因:普通去重不能去除对象。
解决方法:可看数组中有对象去除

移动端1px问题

原因:手机分辨率高,它的实际物理像素数更多了,不同手机屏幕分辨率不同,一般都差不多2倍左右,所以显得更粗。
解决方法:可以参考第二篇CSS的11题。

移动端点击穿透问题

原因

  • 点击蒙层上的关闭按钮,蒙层消失后触发了按钮下面元素的click事件
  • 如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转
  • 这次没有蒙层,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了.
    解决方法
    最优解决方法——只用touch
    最简单的解决方案,完美解决点击穿透问题
    把页面内所有click全部换成touch事件( touchstart、touchmove、touchend)

项目中遇到bug总结:

基本上都是遇到一些样式的Bug,逻辑上的想想就解决了,没什么难的。

后言

为什么离职?

多主观少客观
参考:

  • 我在上一家公司XX能力已经得到了充分的锻炼,现在想去一个更大的平台提升自己的技能,通过了解,贵公司也正好符合我的期待,所以想来挑战一下。

  • 其实上一家公司的工作氛围特别好,大家互相帮助能学习成长很多,但因为贵公司XXX特别吸引我,而我也正好有进一步提升发展的打算,所以才决定来试一试。

面试结尾—— 面试官问:还有什么要问的?

  • 为了更好地胜任这个岗位,我还需要补充哪些前端技能?
  • 前端在公司的发展前景是怎样的?有什么晋升机制?在什么条件下,可以获得晋升机会?
  • 对于未来加入贵公司前端团队,你对我有什么期望?

总结

每天学习一点,更进步一点
祝:大家早日找到理想的工作~
码字不易,持续更新中…

先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号