前端面试题

文章目录

1 . CSS与HTML

1 .1 什么是BFC

  • BFC(块级格式上下文) BFC是一个独立渲染的区域 , 它不会影响到外部的元素
  • BFC的特征
    • 计算BFC的高度时,浮动的元素也参与计算
    • BFC不会影响到外部元素
    • BFC内部的元素是重直排列的
    • BFC区域不会与float元素重叠
  • 如何创建BFC
    • position设置为absolute(绝对定位)或者flxed(固定定位)
    • float不为none
    • overflow设置为hidden
    • display设置为inline-block(行内块元素)或者inline-table(块级表格)或者flex

1 .2 如何理解HTML5的语义化

  • 语义化标签理解就是什么标签做什么事
    • header - 标题
    • nav - 导航
    • article -文章
    • aside - 侧边栏
    • footer - 页脚
  • 语义化标签的好处
    • 代码结构层次清晰 , 提高了用户体验
    • 利用SEO , 语义化能和搜索引擎建立更好的联系 , 优化了搜索
    • 便于团队开发与维护 , 语义化更具有可读性

1.3 H5以及CSS3的新特性

  • H5的新特性
    • 自定义属性data-id
    • 语义化标签(header , nav , footer , aside , article , section)
    • 音视频(audio , video)
    • 本地存储(localSrorage) 用于长期保存到整个网站中的数据 , 保存的数据需要手动删除
    • 会话存储(`sessionStorage``) 临时保存的数据 , 页面一刷新数据就丢失
    • 表单控件 (data , time , url , file , tel )
  • C3新特性
    • 盒子模型 : box-sizing
    • 自定义动画 animate @keyform
    • 颜色渐变 liner-gradient , radial-gradient
    • 媒体查询多栏布局 @media screen and (width:800px){ ....}
    • 弹性布局 flex

1 .4 display:none与visibility:hidden的区别

  • display:none特征

    • 该元素下的元素会进行隐藏 , 占据的空间会消失
    • 会引起回流(重排)和重绘
  • visibility : hidden特征

    • 元素不可见 , 但是仍然占据位置
    • 会引起重绘

1 .5 position的值有哪些

  • 静态定位 : static 默认值不脱离文档流 , 设置(top ,left ,bottom , left) 不生效

  • 绝对定位 : absolute 绝对定位一般找带有定位的父元素 , 如果找不到就相当于游览器进行定位 , 设置绝对定位后元素会脱离正常的文档流 不在占用空间 , 左右magin : auto 将会失效 , 通过 (top ,left ,bottom , left)来决定元素位置

  • 相对定位 : relative 设置相对定位 左右magin : auto 仍然有效 , 不脱离文档流

  • 固定定位 : fixed 会脱离文档流

  • 黏贴定位 : sticky 基于用户的滚动位置来定位。当页面滚动超出目标区域时,它的表现就像 position:fixed;同时黏贴定位必须添加 (top ,left ,bottom , left)中的一个位置才有效

    定位问题参考

    1 .6 CSS的盒子模型

  • 盒子模型组要分为标准盒子模型以及怪异盒模型

    • 在标准盒子模型中一个元素所占的总宽度=width(content)+padding(左右)+margin(左右)+padding(左右),元素的高度同理也是一样的。
    • IE盒子模型也称怪异盒子模型 : 一个元素所占的总宽度=width+margin(左右外边距),(即width包含了border(边框)+padding(内边距)+content)元素的高度同理也是一样的
  • 通过box-sizing设置标准盒子模型和怪异盒子模型

    • box-sizing:border-box 设置为怪异盒子模型时, 变成内减盒子(既padding不会撑大盒子)

    1. 7 CSS单位中px , em , 和rem的区别

  • px像素 , 绝对单位,是相对于显示器屏幕分辨率而言的
  • 1.em和rem区别
  • 共同点:都是相对单位,都是相对元素字体大小
  • 不同点:参考元素不同
    • em : 参考元素自身字体大小
    • rem : 参考根元素(html)字体大小

1 .8 移动端的适配方案

  1. flex布局 自适应布局
  2. rem 适配方案

rem 是一个相对单位,rem 就是 html 根文字的大小

通过媒体查询可以检测视口宽度 然后根据不同视口宽度, 设置不同的根字号完成适配

  1. vw/vh 适配方案

vw就是视口的宽度,vw 是个相对单位。

不管在什么屏幕下, 我们把屏幕分为平均的 100等份。

1 .9 如何实现双飞翼布局

1 . 利用flex布局实现两侧固定中间自适应

  • 父盒子设置display: flex
  • 左右盒子设置固定宽高
  • 中间盒子设置flex:1

2 . 利用BFC块级格式上下文 , 实现两侧固定中间自适应

  • 左右固定宽高 , 进行浮动
  • 中间overflow:hidden

1. 10 为什么要清除浮动 , 清除浮动的方式

  1. 为什么要清除浮动,

设置浮动的盒子会脱标,如果父盒子没有设置高度的话,下面的盒子就会撑上来。

2 . 清除浮动会方式

1 直接给父元素添加高度
2.额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear:both;)
3.父级添加overflow:hidden
4.使用after伪元素清除浮动

    .clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
        content: "";
        display: block;
        height: 0;
        clear:both;
        visibility: hidden;
    }
    .clearfix{
        *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/

5.使用before和after双伪元素清除浮动

 .clearfix:after,.clearfix:before{
        content: "";
        display: table;
    }
    .clearfix:after{
        clear: both;
    }
    .clearfix{
        *zoom: 1;
    }

1 .11简述什么是magin合并(盒子塌陷)以及解决方案

  • 什么是盒子塌陷
  • 就是互相嵌套的块级元素,设置magin-top时子元素会作用到父元素上
  • 造成这样的原因是:
  • 是边距重叠造成的。一个盒模型如果没有上边框,那么它的上边距应该和其文档流中的第一个子元素的上边距重叠。
  • 解决方案
  • 为父元素设置padding : (会撑大盒子模型)
  • 为父元素设置border。(会撑大盒子模型)
  • 为父元素设置 overflow: hidden 。 (推荐使用)
  • 设置position:absolute 绝对定位

1,12 link与@import的区别

<head>
    <!-- link是标签,引入外部样式表 -->
    <link rel="stylesheet" href="./a.css">
    <style>
        /* @import 在css环境中 导入外部css */
        @import url('./b.css');
        .box{
          width: 100px;
          height: 100px;
          background: green;
        }
    </style>
</head>
  • 区别在于
  • link属于html标签 , @import在css中使用时导入外部样式
  • 页面在加载时link会同时加载 , 但是@import引入的css要等页面加载完再加载
  • link引入的样式权重大于@import导入的样式权重

1.13画个小于1px的线

对于安卓需要使用到伪元素,只需要把该伪元素添加到你想要的元素中就可以了,比如:

<div class="text">
    hello world!
</div>
.text{
    position:relative;
}
.text:after{
    content: " ";
    position: absolute;
    bottom: 0;
    right: 0;
    height: 1px;
    border-bottom: 1px solid #d9d9d9;
    color: #d9d9d9;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scaleY(.5);
    transform: scaleY(.5);
    left: 0;
    z-index: 2;
}

1.14vant适配移动端750设计稿

参考答案

1.15 flex布局

flex布局

2 JavaScript

2 .1 JS的基本数据类型以及引用类型

  • 基本数据类型Number , String , Boolean , Null , undefined
  • 引用类型 : Function Object Array

2 . 2 null与undefined的区别

undefined : 表示变量声明但是没有初始化值
null : 表示一个空指针

  • 两个类型的判断
(typeof null)   // 返回Object
typeof undefined  // undefined
  • null==undefined // true
  • null===undefined //false

2 .3 JS中什么情况下会返回undefined

  1. 访问了声明 , 但是没有经过初始化的值
var aa
consloe.log(aa)  //undefined
//或者
console.log(bb)  //var声明的变量存在变量提升
var bb=10
  1. 访问了对象中不存在的属性
  2. 访问被设置为undefined的变量值
  3. 没用定义函数隐式的返回
function aa(){}
consloe.log(aa())

2 .4 多维数组进行扁平化处理的方式

  1. 递归实现 (利用循环递归的方式,一项一项地去遍历,如果每一项还是一个数组,那么就继续往下遍历,利用递归程序的方法,来实现数组的每一项的连接。)

  2. split 和 toString (数组字符串化)

可以通过 split 和 toString 两个方法来共同实现数组扁平化,由于数组会默认带一个 toString的方法,所以可以把数组直接转换成逗号分隔的字符串,然后再用 split 方法把字符串重新转换为数组,如下面的代码所示:

  const flatten = (arr) => {
    return arr.toString().split(',')
  };
  console.log(flatten([1,[2,3,[4,5]]]));
  1. 数组对象提供的 flat
arr.flat(Infinity)  //Infnity 展开任意深度 , 默认展开一层

reduce , 扩展运算符 进行扁平化参考

2 . 5 如何判断两个对象的相等

  1. Object.is()

Object.is 方法判断但是判断的是这两个对象中的引用地址是否一致 , (不能做两个对象中的内容比较)

  1. 如果简单类型直接比较属性值是否相等
  2. 如果是复杂数据类型 那么判断两个对象的属性长度是否相等
if(Object.keys(obj1).length !== Object.keys(obj2).length) {
   return false;
 }
  1. 如果两个对象属性长度相等,就判断属性的数据类型,根据不同数据类型作出操作
    循环对象的属性判断是否还是对象, 如果还是对象的话就继续回去判断,用Object.prototype.toString.call()比较严谨判断是什么类型
for(let attr in obj1) {
    let a1 = Object.prototype.toString.call(obj1[attr]) == '[object Object]'
}

2 .6 什么是伪数组(类数组) , 如何转化为真数组

  • 具有length
  • 也是按照索引的方式排列
  • 不具有真数组的push , pop 等方法 (使用了会报数组.push is not a function)
  • 伪数组=>真数组
    • 使用ES6新增的Array.form()
    • 通过Array.prototype.slice转换为真正的数组

2 .7 如何遍历对象中的属性

  1. Object.keys 获取对象中的属性
  2. for in 遍历获取对象中的属性
  • 区别在于 : 利用for in进行遍历时还会遍历原型链上的属性
  • 原型链上的可枚举属性可以利用hasOwnproperty()过滤掉

2 .8 JS中的作用域 , 预解析 , 与变量声明提升

  • 作用域

    • 全局作用域 : 在函数最外层定义的变量 , 对于任何函数内部都可以访问
    • 局部作用域 : 只在固定的代码片段可以访问到
    • 块级作用域 : 就是用let 或者const 进行声明的变量 只在{ } 内有效 , 如 if while 等
  • 预解析(变量提升)

    • 把变量的声明提升到当前作用域的最前面 , 只会提升声明不会进行赋值
function fn(){
    console.log(a) //undefied
    var a=10
}

2 .9 事件捕获 , 事件冒泡

addEventListener 第三个参数值布尔值 , 如果为true 就表示捕获 , 默认为false 为冒泡事件
事件捕获 : 就是触发同类型事件(click()事件) 从最外层到最内层执行
事件冒泡 : 触发同类型的事件(click()事件) 从 最内层到最外层进行执行

阻止事件冒泡的方法 e.stopPropagation()
阻止默认行为的方法 : e.preventDefault

2 .10 事件委托

  • 1.什么是事件委托
    • 给父元素注册事件,委托给子元素处理
  • 2.事件委托原理:事件冒泡
  • 3.事件委托注意点
    • this : 指向父元素
    • e.target : 指向触发事件的子元素
  • 4.事件委托场景 : 给动态新增元素注册委托事件
  • 5 . 事件委托的优点 : 减少了dom操作,优化了游览器的执行性速度
  • 6 缺点 :

层级过多,冒泡过程中,可能会被某层阻止掉
事件委托基于事件的冒泡对于不冒泡的事价不支持

2.11 描述new一个对象的过程?

  1. 创建了一个空的JS对象(既{}
  2. 将空对象的原型prototype指向构造函数的原型
  3. 将空对象做为构造函数的上下文(改变this的指向
  4. 为新对象添加属性

2.12 什么闭包与使用场景

  • 定义 : 子函数访问父函数中的变量
    function father(){
			const a=10
			return function son(){
          console.log('a')   // 10
			 }
		}
		let fun =father()
		fun()
  • 优缺点
  1. 闭包的优点 : 延伸了变量的作用范围 , 私有化变量防止被污染
  2. 闭包的缺点 :导致函数变量一直保存在内存中 , 过多的闭包会导致内存泄漏
  3. 闭包导致的内存泄漏如何销毁 : 用完之后手动销毁 ,把函数致为null
  • 使用场景
 1. setTimeout
   * 原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。
 2.函数作为返回值
 3.封装防抖函数

2.13 什么是内存泄漏,哪些操作会造成内存泄漏

  • 内存泄漏

    • 简单解释就是内存空间使用完毕后没有进行回收
  • 会造成内存泄漏的操作

    1. 意外的全局变量 , 函数中意外的定义了全局变量,每次执行该函数都会生成该变量,且不会随着函数执行结束而释放。
    2. 未清除的定时器
    3. 闭包引起内存泄漏
    4. console.log console.log的对象是不能被垃圾回收

2.14 什么是原型 ,什么是原型链

详细参考答案

  • 原型链作用 : 实现面向对象继承
  • 对象访问原型链规则: 就近原则
    • 先访问自己,自己没有找原型,原型没有找原型的原型,直到原型链终点。 如果还找不到,属性则获取undefined,方法则报错xxx is not defined

2.15 如何判断this的指向

  1. 以函数的形式调用时,this永远都是window。比如fun();相当于window.fun();

  2. 以方法的形式调用时,this是调用方法的那个对象

  3. 以构造函数的形式调用时,this是新创建的那个对象

  4. 使用call和apply调用时,this是指定的那个对象

  5. 箭头函数(箭头函数没有this):箭头函数的this看外层是否有函数 如果有,外层函数的this就是内部箭头函数的this 如果没有,就是window

  6. 特殊情况:通常意义上this指针指向为最后调用它的对象。这里需要注意的一点就是如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例

2.16 箭头函数与普通函数的区别

  • 普通函数
  1. 可以通过bind call apply 改变this的指向
  2. 可以使用new 关键字
  • 箭头函数
  1. 本身没有this
  2. 不能通过bind , call ,apply 改变this的指向
  3. 不能使用new 关键字 因为箭头函数没有constuctor
  4. 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest 参数代替
  5. 不可以使用yield命令 ,因此箭头函数不能用作Generator函数

2.17 JS执行原理(Event Loop事件循环、微任务、宏任务)

在这里插入图片描述

1.1-事件循环Event Loop概念介绍

​ 事件循环Event Loop又叫事件队列,两者是一个概念

  • 1.什么是事件循环 : 浏览器解析执行js代码的一种运行机制(执行规则)
    • 事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规则。
      • 在js中讨论事件循环是没有意义的, : 事件循环不属于js代码本身的范畴,而是属于js编译器的范畴
        • 说人话: js代码可以理解为是一个人在公司中具体做的事情, 而 事件循环 相当于是公司的一种规章制度。 两者不是一个层面的概念。
1.2-微任务、宏任务概念介绍
  • 1.微任务与宏任务就属于js代码的范畴

  • 2.js代码主要分为两大类: 同步代码、异步代码

  • 3.异步代码又分为:微任务与宏任务

  • 同步任务:同步任务不需要进行等待,必须立即看到执行结果,比如console

  • 异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求

异步任务,又可以细分为宏任务微任务。下面列举目前学过的宏任务和微任务。

  • 异步宏: script标签事件处理函数定时器回调ajax回调
  • 异步微: promise.then() await/async
1.3 事件循环规则 :
  (1)先‘解析’默认script标签,进入第一个宏任务(默认宏)
  (2)判断代码是同步还是异步
  (3)如果是同步: 立即‘执行’
  (4)如果是异步:  微任务放入微队列, 宏任务放入宏队列
  (5)当前同步执行完毕之后,开始执行异步队列
  (6)先清空微任务队列,之后再‘解析’宏任务队列,此时完成一次事件循环
  (7)按照以上步骤反复解析执行每一个宏任务(事件循环就是按照相同的规则反复循环解析执行代码) 

1.18 =====Object.is的区别

Object.is 主要是判断-0与+0是否相等 //false ,同时可以处理NAN是否相等

1.19 如何判断JS变量的数据类型?

1. typeof
2. instanceof
3. constructor
4.

注意:返回值是一个字符串,字符串里的内容固定格式为 [object 判断类型的结果]

1.20函数柯里化

简单理解就是:将一个接受多个参数的函数,转化为接收一个参数的函数,最后做统一处理

       // 简单的相加函数
		 	var add = function (x, y,z) {
				return x + y + z
			}
			// 调用:
		    console.log(add(10, 20,30));	
			// 柯里化以后(柯里化闭包)
			const curring=(x)=>(y)=>(z)=> x+y+z
			console.log(curring(10)(20)(30));

用途

  • 让函数职责单一
  • 代码复用更加明确
  • 函数柯里化是对闭包的一种应用形式,延迟计算、参数复用、动态生成函数(都是闭包的用途)。

手写柯里化

2.21 说一说跨域是什么?如何解决跨域问题?

答题思路参考 :同源限制、协议、域名、端口、CORS、node中间件、JSONP、postmessage

  • 跨域

当前页面中的某一个接口请求的地址和当前页面的地址如果协议,域名,端口有一项不同就会产生跨域

  • 跨域限制的原因

浏览器为了保证网页的安全,出的同源策略

  • 跨域的报错信息
    在这里插入图片描述
  • 跨域解决方案
      1. cros :目前最常用的一种解决方法,通过设置后端允许跨域 res.setHeader(‘Access-Control-Allow-Origin’, ‘*’);
        res.setHeader(“Access-Control-Allow-Methods”, “GET, PUT, OPTIONS, POST”);
    • 2. node中间件 ,nginx反向代理 跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。

    • 3.JSONP :利用script标签可以跨域请求资源,将回调函数做为参数拼接在url中,后端收到请求,调用该回调函数,并将数据作为参数返回去,需要设置响应头类型为javascript

    • postmessage :H5新增API,通过发送和接受API实现跨域通信

2.22 defer与async的区别

关键 :加载解析,异步 阻塞

  • defer和async加载script和html解析同时进行,加载完script,async立刻执行,defer在html解析结束后执行
  • 加上async属性,加载JS文档和渲染文档可以同时进行(异步),当JS加载完成,JS代码立即执行,会阻塞HTML渲染。
  • 加上defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),当HTML渲染完成,才会执行JS代码

2.23游览器输入url发生了什么

  1. URL解析 :判断是搜索内容还是请求URL
  2. 查找本地缓存:如果有缓存直接返回给页面,没有缓存则进入网络请求阶段(注意点:这里涉及强缓存以及协商缓存)
  3. DNS域名解析
  4. 通过三次握手建立TCP连接
  5. 发生HTTP请求,处理响应信息
  6. 通过四次挥手,断开TCP连接
  7. 游览器进行页面渲染
  8. JS引擎进行解析
  • 页面渲染流程图
    在这里插入图片描述

2.24 游览器是如何渲染页面的(回流与重绘)

参考答案

2.25字符串的翻转

字符串转数组
反转数组 :resever方法

2.26继承的方式有哪些

继承方式参考

2.27回流与重绘

  1. reflow(重排):渲染树节点发生改变,但不影响该节点在页面当中的空间位置及大小。譬如某个div标签节点的背景颜色、字体颜色等等发生改变,但是该div标签节点的宽、高、内外边距并不发生变化,此时触发浏览器重绘
  2. repaint(重绘):当渲染树节点发生改变,影响了节点的几何属性(如宽、高、内边距、外边距、或是float、position、display:none;等等),导致节点位置发生变化,此时触发浏览器重排(reflow),需要重新生成渲染树。譬如JS为某个p标签节点添加新的样式:“display:none;”。导致该p标签被隐藏起来,该p标签之后的所有节点位置都会发生改变。此时浏览器需要重新生成渲染树,重新布局,即重排
  • 减少重排,优化性能
  1. 不要一个个的修改 DOM 的样式,应通过 class 来修改
  2. 可以将需要多次修改的DOM元素设置display:none,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘)

2.28什么是递归

在这里插入图片描述

2.29常用的数组方法有哪些?

reverse( )方法将数组中元素的位置颠倒,并返回该数组。该方法会改变原数组。

sort( )方法用[原地算法]对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的

concat( ) 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

find( )方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 [undefined]

findIndex方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

includes方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

indexOf方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。 (通常用它判断数组中有没有这个元素)

join 方法将一个数组(或一个[类数组对象])的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

pop方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

posh方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

shift方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

unshift( )方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组**)**。

splice( )方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

参考返回值

2.30 数组有哪几种循环方式?分别有什么作用?

map( )方法 映射数组。 对数组每一个元素进行映射处理,得到一个全新数组

filter( )方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

forEach( )方法对数组的每个元素执行一次提供的函数。

some( )方法测试是否至少有一个元素可以通过被提供的函数方法。该方法返回一个Boolean类型的值。

every( )方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

findIndex( )方法获取某个元素下标 可以深度查找, findIndex一般用于对象数组

reduce( )方法 逐个遍历数组元素,每一步都将当前元素的值与上一步的计算结果相加 参数1上次返回的结果, 参数2当前元素, 参数3当前元素的下标

2.31 常用的字符串方法有哪些?

trim( )方法会从一个字符串的两端删除空白字符。在这个上下文中的空白字符是所有的空白字符 (space, tab, no-break space 等) 以及所有行终止符字符(如 LF,CR)。

charAt( )方法从一个字符串中返回指定位置的字符。

concat( )方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。

includes( )方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。

**indexOf( ) **方法返回调用它的 [String] 对象中第一次出现的指定值的索引,从 fromIndex 处进行搜索。如果未找到该值,则返回 -1。

match( )方法检索返回一个字符串匹配正则表达式的的结果。

padStart( )方法用另一个字符串填充当前字符串(重复,如果需要的话),以便产生的字符串达到给定的长度。填充从当前字符串的开始(左侧)应用的。 (常用于时间补0)

replace( )方法返回一个由替换值(replacement)替换一些或所有匹配的模式(pattern)后的新字符串。模式可以是一个字符串或者一个[正则表达式],替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。

原字符串不会改变。

slice( )方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。

split( )方法使用指定的分隔符字符串将一个[String]对象分割成字符串数组,以将字符串分隔为子字符串,以确定每个拆分的位置。

substr( )方法返回一个字符串中从指定位置开始到指定字符数的字符。

2.32 require与import的区别

    1,require是CommonJS规范的模块化语法,import是ECMAScript 6规范的模块化语法;
    2,require是运行时加载,import是编译时加载;
    3,require可以写在代码的任意位置,import只能写在文件的最顶端且不可在条件语句或函数作用域中使用;
    4,require通过module.exports导出的值就不能再变化,import通过export导出的值可以改变;
    5;require通过module.exports导出的是exports对象,import通过export导出是指定输出的代码;
    6,require运行时才引入模块的属性所以性能相对较低,import编译时引入模块的属性所以性能稍高。

2.33 深浅拷贝

浅拷贝:拷贝基本数据类型为他的值,拷贝引用数据类型为地址,但当对象的属性值是引用类型时,进行修改时,引用指向的值改变时也会跟着变化。
可以使用 for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat()

深拷贝:在内存中开辟一个新的栈空间保存新的数据,修改新数据不会影响到原数据,开发中常用的方法有:loadsh 中的_.cloneDeep()方法,JSON.stringify()

  • JSON拷贝会出现的问题
    在这里插入图片描述

3 ES6

3.1 call ,apply , bind的区别

  • 共同点

都可以改变this的指向

  • 不同点
  • call 和bind的传参 是参数列表
  • apply传参是一个数组
  • call和apply改变this都是对函数进行直接调用,而bind方法改变this返回的仍是一个函数,绑定的函数不会执行;

3.2 let、const和var区别

  1. var 存在变量提升,let 和 const 不存在变量提升
  2. var允许重复声明 , 但是let 和 const 不允许重复声明
  3. var 不存在暂时性死区 ,let 和 const 存在暂时性死区
  4. let 和 const 会产生块级作用域
  5. const 声明的同时需要赋值 , 如果是基础数据类型不能重复赋值 ,如果是引用类型则可以修改内部的值

3.3 for in与for of的区别

  1. for…in循环出的是key,for…of循环出的是value
  2. 循环对象属性时,使用for...in , 实际是为循环”enumerable“(可枚举)对象而设计的。Js基本数据类型自带的原型属性不可枚举,通过Object.defineProperty0方法指enumeralbe为false的属性不可枚举。
  3. for…of数组对象都可以遍历,它是ES6中新增加的语法。一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for…of循环。for…of遍历对象需要通过和Object.keys()

3.4数据结构Set,Map的区别

  1. 应用场景Set 用于数组去重,Map 用于数据存储
  2. Set 中成员不能重复,只有键值,没有健名,类似于数组,可以遍历
  3. Map本质上是键值对的集合,类似于集合,可以遍历,可以跟各种数据交换格式
    详细解答参考

3.5 Promise对象解释

  1. Promise是异步编程的解决方法 ,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,解决的回调地狱,自己身上有all , reject , resolve,race,等方法,原型上有then,catch等方法
  2. Promise 三种状态 ,pending(待定) 初始状态 , fulfilled(实现) 成功状态,rejected(被否定)失败状态
  3. Promise两个过程,pending=>fulfilled(初始状态到成功),pending=>rejected (初始状态到失败)
    在这里插入图片描述

3.6Promise.all哪怕一个请求失败了也能得到其余正确的请求结果的解决方案

Promise.all默认只要有一个错误就直接返回错误。promise.all中任何一个promise 出现错误的时候都会执行reject,导致其它正常返回的数据也无法使用
Promise.all(
  [
    Promise.reject({ code: 500, msg: "服务异常" }),
    Promise.resolve({ code: 200, list: [] }),
    Promise.resolve({ code: 200, list: [] })
  ].map(p => p.catch(e => e))
)
  .then(res => {
    console.log("res=>", res);
  })
  .catch(error => {
    console.log("error=>", error);
  });
res=> [ { code: 500, msg: '服务异常' },
  { code: 200, list: [] },
  { code: 200, list: [] } ]
核心内容是map方法,map的每一项都是promise,catch方法返回值会被promise.reslove()包裹,这样传进promise.all的数据都是resolved状态的。
 
// 使用Promise.all 其中id为69的商品,返回失败,会导致整个Promise接受到reject状态.
// 所以进行改造, p catch 得到的err  为返回失败抛出的信息, 进行置空
.map(p => p.catch(err => '')))

3.7async与await的原理

  1. async与await是一种同步的写法,但是还是异步的操作,两者必须配合使用
  2. 函数前面的async关键字,表明该函数内部有异步操作,调用该函数时会返回一个Promise对象
  3. await语句后的Promise对象变成reject状态时,那么整个async函数会中断,后面的程序不会继续执行
  • 使用场景
    • 在项目中,在发送第一次Ajax请求拿到第一次的数据,使用第一次ajax返回的数据来执行第二次ajax接口的调用

4 webpack

4.1谈谈对Webpack的理解

  1. webpack是一个模块打包工具,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件,(在webpack中,一切模块皆为模块,通过loader转换文件,通过plugin注入钩子
  2. 它可以很好的管理,打包开发中所用的HTML,CSS,JavaScript和静态文件(图片,文字)等,让开发更高效
  3. 对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源

4.2 Webpack的优点(或基本功能)

  1. 代码转换,TypeScript编译成javaScript,SCSS编译成CSS等
  2. 文件优化,压缩javaScript,CSS,HTML代码,压缩合成图片等
  3. 代码分割,提取多个页面的公共代码,提取首屏不需要执行的部分代码让其异步加载
  4. 模块合并,在采用模块化的项目有很多模块和文件,需要构建功能吧模块分类合并成一个文件
  5. 自动刷新,监听本地源代码的变化,自动构建,刷新游览器
  6. 自动发布,更新完代码后,自动构建出线上发布并传输给发布系统

4.3说说常用的loader

  1. file-loader:把文件输出到一个文件夹中,在代码中通过相对的URL去引用输出的文件(处理图片和文件)
  2. url-loader:与file-loader类似,区别是用户可以设置一个阀值,小于这个阀值用base64进行编码(处理图片和字体)
  3. css-loader :加载CSS,支持模块化,压缩,文件导入
  4. style-loader:把CSS代码注入到JavaScript中,通过DOM操作去加载CSS
  5. babel-loader:把ES6转化成ES5
  6. Less-loader:将less代码转化为CSS

4.4 有哪些常用Plugin

  • html-webpack-plugin:根据模板页面生成打包的 html 页面

  • uglifyjs-webpack-plugin:不支持 ES6 压缩 ( Webpack4 以前)

  • mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载

  • clean-webpack-plugin: 目录清理

  • copy-webpack-plugin: 拷贝文件

  • webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)
    ###4.5 Webpack的loader和plugin的区别

  • 不同的作用:

    • loader 译为加载器,因为Webpack原生只能解析JS文件,如果想将其他文件也打包就会用到loader,主要作用就是让Webpack拥有加载和解析的能力
    • Plugin 译为插件 用于扩展Webpack的功能,使其不再局限于功能的加载,例如: 打包优化、资源管理、环境变量注入
  • 不同的用法

4.6 Webapck的构建流程

在这里插入图片描述

  1. 执行 npm run build
  2. webpack 首先回去webpack.comfig.js中去查找是否有自定义命令改变的入口和出口
  3. 如果有,就会去执行配置文件中的命令,如何没有就会执行默认命令
  4. 然后开始查找各种依赖关系开始打包
    注意
    • 所有想要被打包的资源都要和入口文件产生关系才能被打包
    • webpack打包的默认入口:src/index.js文件,默认出口dist/main.js

总体打包流程参考

4.7 webpack与vite的区别

  • Vite是基于esbuild预构建依赖。而esbuild是采用go语言编写,因为go语言的操作是纳秒级别,而js是以毫秒计数,所以vite比用js编写的打包器快10-100倍。
  • webpack: 分析依赖=> 编译打包=> 交给本地服务器进行渲染。首先分析各个模块之间的依赖,然后进行打包,在启动webpack-dev-server,请求服务器时,直接显示打包结果。webpack打包之后存在的问题:随着模块的增多,会造成打出的 bundle 体积过大,进而会造成热更新速度明显拖慢。
  • vite: 启动服务器=> 请求模块时按需动态编译显示。是先启动开发服务器,请求某个模块时再对该模块进行实时编译,因为现代游览器本身支持ES-Module,所以会自动向依赖的Module发出请求。所以vite就将开发环境下的模块文件作为浏览器的执行文件,而不是像webpack进行打包后交给本地服务器。

5.TS面试题

5.1 unknow ,any, never的区别

  • any:任意类型的变量
  • unknown: 表示未知类型
    注意 : unknown与any类似 但使用前必须进行断言或守卫
  • never:永不存在的值的类型

unknown表示未知类型与·any·不同的是 unknown类型的变量不允许被any或unknown以外的变量赋值,也不允许执行unknown类型变量的
在这里插入图片描述

nerve 抛出异常或函数中执行无线循环的代码(死循环)的函数返回值类型

//抛出异常
function error(msg:string):never{
    throw new Error(msg)
}//抛出异常会直接中断程序运行,这样程序就运行不到返回值那一步了,即具有不可到达的终点,也就永不存在返回了

//死循环
function loopForever():never{
    while(true){}
} //同样程序永远无法运行到函数返回值那一步  即永不存在返回

5.2 type与interface的区别

  1. interface只能为对象指定类型,type可以为任何类型指定类型
  2. 接口继承方式不同
interface Type3D extends Type2D
type Type3D={z:Number} & Type2D

3. interface可以重复的为某个接口定义属性和方法, (同名的接口会进行合并),但是type不行

interface Type3D{
name:string,
say():void
}
interface Type3D{
age:18
}

5.3枚举类型

  • 枚举就是一个对象的所有可能取值的集合
    项目中最常用的就是后端返回的字段使用 0 - 6 标记对应的日期,这时候就可以使用枚举可提高代码可读性,如下:
enum Days {
  Sun,
  Mon,
  Tue,
  Wed,
  Thu,
  Fri,
  Sat,
}
console.log(Days['Sun'] === 0) // true
console.log(Days['Mon'] === 1) // true
console.log(Days['Tue'] === 2) // true
console.log(Days['Sat'] === 6) // true

场景二:利用枚举实现后端日常返回 0、1 等状态的时候,用来枚举成按钮的启用效果

5.4 泛型

泛型:指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。
泛型参考

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值