文章目录
- 1 . CSS与HTML
- 2 JavaScript
- 2 .1 JS的基本数据类型以及引用类型
- 2 . 2 null与undefined的区别
- 2 .3 JS中什么情况下会返回undefined
- 2 .4 多维数组进行扁平化处理的方式
- 2 . 5 如何判断两个对象的相等
- 2 .6 什么是伪数组(类数组) , 如何转化为真数组
- 2 .7 如何遍历对象中的属性
- 2 .8 JS中的作用域 , 预解析 , 与变量声明提升
- 2 .9 事件捕获 , 事件冒泡
- 2 .10 事件委托
- 2.11 描述new一个对象的过程?
- 2.12 什么闭包与使用场景
- 2.13 什么是内存泄漏,哪些操作会造成内存泄漏
- 2.14 什么是原型 ,什么是原型链
- 2.15 如何判断this的指向
- 2.16 箭头函数与普通函数的区别
- 2.17 JS执行原理(Event Loop事件循环、微任务、宏任务)
- 1.18 `==`与`===` 与`Object.is`的区别
- 1.19 如何判断JS变量的数据类型?
- 1.20函数柯里化
- 2.21 说一说跨域是什么?如何解决跨域问题?
- 2.22 defer与async的区别
- 2.23游览器输入url发生了什么
- 2.24 游览器是如何渲染页面的(回流与重绘)
- 2.25字符串的翻转
- 2.26继承的方式有哪些
- 2.27回流与重绘
- 2.28什么是递归
- 2.29常用的数组方法有哪些?
- 2.30 数组有哪几种循环方式?分别有什么作用?
- 2.31 常用的字符串方法有哪些?
- 2.32 require与import的区别
- 2.33 深浅拷贝
- 3 ES6
- 4 webpack
- 5.TS面试题
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
- position设置为
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 移动端的适配方案
- flex布局 自适应布局
- rem 适配方案
rem 是一个相对单位,rem 就是 html 根文字的大小
通过媒体查询可以检测视口宽度 然后根据不同视口宽度, 设置不同的根字号完成适配
- vw/vh 适配方案
vw就是视口的宽度,vw 是个相对单位。
不管在什么屏幕下, 我们把屏幕分为平均的 100等份。
1 .9 如何实现双飞翼布局
1 . 利用flex布局实现两侧固定中间自适应
- 父盒子设置display: flex
- 左右盒子设置固定宽高
- 中间盒子设置flex:1
2 . 利用BFC块级格式上下文 , 实现两侧固定中间自适应
- 左右固定宽高 , 进行浮动
- 中间overflow:hidden
1. 10 为什么要清除浮动 , 清除浮动的方式
- 为什么要清除浮动,
设置浮动的盒子会脱标,如果父盒子没有设置高度的话,下面的盒子就会撑上来。
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布局
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
- 访问了声明 , 但是没有经过初始化的值
var aa
consloe.log(aa) //undefined
//或者
console.log(bb) //var声明的变量存在变量提升
var bb=10
- 访问了对象中不存在的属性
- 访问被设置为undefined的变量值
- 没用定义函数隐式的返回
function aa(){}
consloe.log(aa())
2 .4 多维数组进行扁平化处理的方式
-
递归实现 (利用循环递归的方式,一项一项地去遍历,如果每一项还是一个数组,那么就继续往下遍历,利用递归程序的方法,来实现数组的每一项的连接。)
-
split 和 toString (数组字符串化)
可以通过 split 和 toString
两个方法来共同实现数组扁平化,由于数组会默认带一个 toString的方法,所以可以把数组直接转换成逗号分隔的字符串,然后再用 split 方法把字符串重新转换为数组,如下面的代码所示:
const flatten = (arr) => {
return arr.toString().split(',')
};
console.log(flatten([1,[2,3,[4,5]]]));
- 数组对象提供的
flat
arr.flat(Infinity) //Infnity 展开任意深度 , 默认展开一层
2 . 5 如何判断两个对象的相等
- Object.is()
Object.is
方法判断但是判断的是这两个对象中的引用地址是否一致 , (不能做两个对象中的内容比较)
- 如果简单类型直接比较属性值是否相等
- 如果是复杂数据类型 那么判断两个对象的属性长度是否相等
if(Object.keys(obj1).length !== Object.keys(obj2).length) {
return false;
}
- 如果两个对象属性长度相等,就判断属性的数据类型,根据不同数据类型作出操作
循环对象的属性判断是否还是对象, 如果还是对象的话就继续回去判断,用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
转换为真正的数组
- 使用ES6新增的
2 .7 如何遍历对象中的属性
- Object.keys 获取对象中的属性
- 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一个对象的过程?
- 创建了一个空的JS对象(
既{}
) - 将空对象的原型
prototype
指向构造函数的原型 - 将空对象做为构造函数的上下文(
改变this的指向
) - 为新对象添加属性
2.12 什么闭包与使用场景
- 定义 : 子函数访问父函数中的变量
function father(){
const a=10
return function son(){
console.log('a') // 10
}
}
let fun =father()
fun()
- 优缺点
- 闭包的优点 : 延伸了变量的作用范围 , 私有化变量防止被污染
- 闭包的缺点 :导致函数变量一直保存在内存中 , 过多的闭包会导致内存泄漏
- 闭包导致的内存泄漏如何销毁 : 用完之后手动销毁 ,把函数致为
null
- 使用场景
1. setTimeout
* 原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。
2.函数作为返回值
3.封装防抖函数
2.13 什么是内存泄漏,哪些操作会造成内存泄漏
-
内存泄漏
- 简单解释就是内存空间使用完毕后没有进行回收
-
会造成内存泄漏的操作
- 意外的全局变量 , 函数中意外的定义了全局变量,每次执行该函数都会生成该变量,且不会随着函数执行结束而释放。
- 未清除的定时器
- 闭包引起内存泄漏
console.log
console.log的对象是不能被垃圾回收
2.14 什么是原型 ,什么是原型链
- 原型链作用 :
实现面向对象继承
- 对象访问原型链规则: 就近原则
- 先访问自己,自己没有找原型,原型没有找原型的原型,直到原型链终点。 如果还找不到,
属性则获取undefined,方法则报错xxx is not defined
- 先访问自己,自己没有找原型,原型没有找原型的原型,直到原型链终点。 如果还找不到,
2.15 如何判断this的指向
-
以函数的形式调用时,this永远都是window。比如fun();相当于window.fun();
-
以方法的形式调用时,this是调用方法的那个对象
-
以构造函数的形式调用时,this是新创建的那个对象
-
使用call和apply调用时,this是指定的那个对象
-
箭头函数(
箭头函数没有this
):箭头函数的this看外层是否有函数 如果有,外层函数的this就是内部箭头函数的this 如果没有,就是window -
特殊情况:通常意义上this指针指向为最后调用它的对象。这里需要注意的一点就是如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例
2.16 箭头函数与普通函数的区别
- 普通函数
- 可以通过bind call apply 改变this的指向
- 可以使用
new
关键字
- 箭头函数
- 本身没有this
- 不能通过bind , call ,apply 改变this的指向
- 不能使用
new
关键字 因为箭头函数没有constuctor
- 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用Rest
参数代替- 不可以使用
yield
命令 ,因此箭头函数不能用作Generator
函数
2.17 JS执行原理(Event Loop事件循环、微任务、宏任务)
1.1-事件循环Event Loop概念介绍
事件循环Event Loop又叫事件队列,两者是一个概念
- 1.什么是事件循环 : 浏览器解析执行js代码的一种运行机制(执行规则)
- 事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规则。
在js中讨论事件循环是没有意义的,
: 事件循环不属于js代码本身的范畴,而是属于js编译器的范畴- 说人话: js代码可以理解为是一个人在公司中具体做的事情, 而 事件循环 相当于是公司的一种规章制度。 两者不是一个层面的概念。
- 事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规则。
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变量的数据类型?
注意:返回值是一个字符串
,字符串里的内容固定格式为 [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
- 跨域
当前页面中的某一个接口请求的地址和当前页面的地址如果
协议,域名,端口
有一项不同就会产生跨域
- 跨域限制的原因
浏览器为了保证网页的安全,出的
同源策略
- 跨域的报错信息
- 跨域解决方案
-
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发生了什么
URL解析
:判断是搜索内容还是请求URL查找本地缓存
:如果有缓存直接返回给页面,没有缓存则进入网络请求阶段(注意点:这里涉及强缓存以及协商缓存)DNS域名解析
通过三次握手建立TCP连接
发生HTTP请求,处理响应信息
通过四次挥手,断开TCP连接
游览器进行页面渲染
- JS引擎进行解析
- 页面渲染流程图
2.24 游览器是如何渲染页面的(回流与重绘)
2.25字符串的翻转
字符串转数组
反转数组 :resever方法
2.26继承的方式有哪些
2.27回流与重绘
reflow(重排)
:渲染树节点发生改变,但不影响该节点在页面当中的空间位置及大小。譬如某个div标签节点的背景颜色、字体颜色等等发生改变,但是该div标签节点的宽、高、内外边距并不发生变化,此时触发浏览器重绘repaint(重绘)
:当渲染树节点发生改变,影响了节点的几何属性(如宽、高、内边距、外边距、或是float、position、display:none;等等),导致节点位置发生变化,此时触发浏览器重排(reflow),需要重新生成渲染树。譬如JS为某个p标签节点添加新的样式:“display:none;”。导致该p标签被隐藏起来,该p标签之后的所有节点位置都会发生改变。此时浏览器需要重新生成渲染树,重新布局,即重排
减少重排,优化性能
- 不要一个个的修改 DOM 的样式,应通过 class 来修改
- 可以将需要多次修改的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区别
- var 存在变量提升,let 和 const 不存在变量提升
- var允许重复声明 , 但是let 和 const 不允许重复声明
- var 不存在暂时性死区 ,let 和 const 存在暂时性死区
- let 和 const 会产生块级作用域
- const 声明的同时需要赋值 , 如果是基础数据类型不能重复赋值 ,如果是引用类型则可以修改内部的值
3.3 for in与for of的区别
- for…in循环出的是
key
,for…of循环出的是value
。- 循环对象属性时,使用
for...in
, 实际是为循环”enumerable“(可枚举)对象而设计的。Js基本数据类型自带的原型属性不可枚举,通过Object.defineProperty0方法指enumeralbe为false的属性不可枚举。for…of
数组对象都可以遍历,它是ES6中新增加的语法。一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for…of循环。for…of遍历对象需要通过和Object.keys()
3.4数据结构Set,Map的区别
- 应用场景
Set
用于数组去重,Map
用于数据存储 Set
中成员不能重复,只有键值,没有健名,类似于数组,可以遍历Map
本质上是键值对的集合,类似于集合,可以遍历,可以跟各种数据交换格式
详细解答参考
3.5 Promise对象解释
- Promise是异步编程的解决方法 ,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,解决的回调地狱,自己身上有
all , reject , resolve,race,
等方法,原型上有then,catch等方法- Promise 三种状态 ,
pending(待定) 初始状态 , fulfilled(实现) 成功状态,rejected(被否定)失败状态
- 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的原理
- async与await是一种同步的写法,但是还是异步的操作,两者必须配合使用
- 函数前面的async关键字,表明该函数内部有异步操作,调用该函数时会返回一个Promise对象
- await语句后的Promise对象变成reject状态时,那么整个async函数会中断,后面的程序不会继续执行
- 使用场景
- 在项目中,在发送第一次Ajax请求拿到第一次的数据,使用第一次ajax返回的数据来执行第二次ajax接口的调用
4 webpack
4.1谈谈对Webpack的理解
- webpack是一个模块打包工具,可以使用它管理项目中的模块依赖,并编译输出模块所需的静态文件,(
在webpack中,一切模块皆为模块,通过loader转换文件,通过plugin注入钩子
) - 它可以很好的管理,打包开发中所用的HTML,CSS,JavaScript和静态文件(图片,文字)等,让开发更高效
- 对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后合并生成优化的静态资源
4.2 Webpack的优点(或基本功能)
代码转换
,TypeScript编译成javaScript,SCSS编译成CSS等文件优化
,压缩javaScript,CSS,HTML代码,压缩合成图片等代码分割
,提取多个页面的公共代码,提取首屏不需要执行的部分代码让其异步加载模块合并
,在采用模块化的项目有很多模块和文件,需要构建功能吧模块分类合并成一个文件自动刷新
,监听本地源代码的变化,自动构建,刷新游览器自动发布
,更新完代码后,自动构建出线上发布并传输给发布系统
4.3说说常用的loader
file-loader
:把文件输出到一个文件夹中,在代码中通过相对的URL去引用输出的文件(处理图片和文件)url-loader
:与file-loader类似,区别是用户可以设置一个阀值,小于这个阀值用base64进行编码(处理图片和字体)css-loader
:加载CSS,支持模块化,压缩,文件导入style-loader
:把CSS代码注入到JavaScript中,通过DOM操作去加载CSSbabel-loader
:把ES6转化成ES5Less-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的构建流程
- 执行 npm run build
- webpack 首先回去
webpack.comfig.js
中去查找是否有自定义命令改变的入口和出口 - 如果有,就会去执行配置文件中的命令,如何没有就会执行默认命令
- 然后开始查找各种依赖关系开始打包
注意
:- 所有想要被打包的资源都要和
入口文件
产生关系才能被打包 - 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的区别
interface
只能为对象
指定类型,type可以为任何类型指定类型- 接口继承方式不同
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 泛型
泛型
:指的是在定义函数/接口/类型时
,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。
泛型参考