前端必看知识点

135 阅读49分钟

描述数组的方法

arr.unshift() 从前面添加元素, 返回值是添加完后的数组的长度

push() 从后面添加元素, 返回值为添加完后的数组的长度

arr.shift() 从前面删除元素, 只能删除一个 返回值是删除的元素

arr.pop() 从后面删除元素, 只能是一个, 返回值是删除的元素

arr.splice(i,n) splice() 方法通过移除或者替换已存在的元素和/或添加新元素就地改变一个数组的内容

str.split() 将字符串转化为数组

arr.sort() sort() 方法默认按照字符串的 Unicode 编码进行排序。它会直接修改原始数组,并返回排序后的数组。

arr.reverse() reverse() 方法就地反转数组中的元素,返回值是反转后的数组

arr.forEach(callback) 遍历数组,无 return 即使有 return, 也不会返回

任何值, 并且会影响原来的数组 

arr.slice(start,end) 切去索引值 start 到索引值 end 的数组,不包含 end

索引的值, 返回值是切出来的数组 (新数组)

arr.concat() 连接两个数组 返回值为连接后的新数组

arr.map(callback) 映射数组(遍历数组),有 return 返回一个新数组 。

arr.filter(callback) 过滤数组, 返回一个满足要求的数组

some() 方法测试数组中是否至少有一个元素通过了由提供的函数实现的测试。如果在数组中找到一个元素使得提供的函数返回 true,则返回 true;否则返回 false。它不会修改数组。

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

ObjectAPI

Object.keys() 静态方法返回一个由给定对象自身的可枚举的字符串键属性名组成的数组。

Object.values() 静态方法返回一个给定对象的自有可枚举字符串键属性值组成的数组。

一个返回的是键、一个返回的值。

Object.create() 静态方法以一个现有对象作为原型,创建一个新对象

Object.is() 静态方法确定两个值是否为相同值。

Object.is() 不等价于 === 运算符。Object.is() 和 === 之间的唯一区别在于它们处理带符号的 0 和 NaN 值的时候。

=== 运算符(和 == 运算符)将数值 -0 和 +0 视为相等,但是会将 NaN 视为彼此不相等。

Object.entries() 静态方法返回一个数组,包含给定对象自有的可枚举字符串键属性的键值对。

Object.defineProperty() 静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象。

Object.prototype.hasOwnProperty() hasOwnProperty() 方法返回一个布尔值,表示对象自有属性(而不是继承来的属性)中是否具有指定的属性。

 

Number.isNaN() 方法确定传递的值是否为 NaN,并且检查其类型是否为 Number。它是原来的全局 isNaN() 的更稳妥的版本。

我们不能使用相等运算符(== (en-US) 和 === (en-US))来判断一个值是否是 NaN,因为 NaN == NaN 和 NaN === NaN 都会返回 false

NaN也属于Number类型,但是它是一个特殊的非数字值

StringAPI

String.prototype.charAt()获取指定索引处的值

String.prototype.charCodeAt()获取指定索引处的ASCII码

String.prototype.trim()方法从字符串的两端清除空格,返回一个新的字符串,而不修改原始字符串。

trimStart() 方法会删除字符串开头的空白字符。

trimEnd() 方法会删除字符串末尾的空白字符。

Html

高度塌陷

当所有的子元素浮动的时候, 且父元素没有设置高度,这时候父元素就会产生高度塌陷。

高度塌陷和下面不是矛盾吗?

在有些情况下,我们没有给父级盒子设置高度 ,而是通过给子盒子设置浮动效果来撑开盒子,达到想要的页面效果,但是设置浮动之后,会影响下面盒子的布局,所以我们需要清除浮动。

清除浮动方式

1: 给父元素单独定义高度

优点: 快速简单, 代码少

缺点: 无法进行响应式布局 清除浮动方式

2: 父级定义 overflow: hidden; zoom: 1 (针对 ie6 的 兼容)

优点: 简单快速、代码少, 兼容性较高

缺点: 超出部分被隐藏, 布局时 要注意 清除浮动方式

3: 在浮动元素后面加一个空标签, clear: both; height: 0;

overflow: hidden 优点: 简单快速、代码少, 兼容性较高。

缺点: 增加空标签, 不利于页面优化 清除浮动方式

4: 父级定义 overflow: auto 第 5 页

优点: 简单, 代码少, 兼容性好

缺点: 内部宽高超过父级 div 时, 会出现滚动条 清除浮动方式

5: 万能清除法:给塌陷的元素添加伪对象 .father: after{ Content:“随便写”; Clear: both; display: block; Height: 0; Overflow: hidden; Visibility: hidden }

优点: 写法固定, 兼容性高

缺点: 代码多

position

1.静态定位 static(了解)

静态定位是元素的默认定位方式,无定位的意思。

静态定位按照标准流特性摆放位置,它没有边偏移

静态定位在布局时很少用到

相对定位是元素在移动位置的时候,是相对于它原来的位置来说的(自恋型)。

绝对定位是元素在移动位置的时候,是相对于它祖先元素来说的(拼爹型)

绝对定位的特点:(务必记住)

  1. 如果没有祖先元素或者祖先元素没有定位,则以浏览器为准定位(Document 文档)。

  2. 如果祖先元素有定位(相对、绝对、固定定位),则以最近一级的有定位祖先元素为参考点移动位置。

  3. 绝对定位不再占有原先的位置。(脱标)

相对定位的特点:(务必记住)

  1. 它是相对于自己原来的位置来移动的(移动位置的时候参照点是自己原来的位置)。

  2. 原来在标准流的位置继续占有,后面的盒子仍然以标准流的方式对待它。

因此,相对定位并没有脱标。它最典型的应用是给绝对定位当祖先元素的。。。(子绝父相)

元素的垂直居中

![文本

描述已自动生成]()

 

 

![图形用户界面

中度可信度描述已自动生成]()

![文本

描述已自动生成]()

juejin.cn/post/706158…

  1. 利用绝对定位,设置 left: 50%  和 top: 50%  现将子元素左上角移到父元素中心位置,然后再通过 translate  来调整子元素的中心点到父元素的中心。该方法可以不定宽高

实现水平居中,top不要设值。Translate第二个参数设为百分之零。

  1. 利用绝对定位,子元素所有方向都为 0 ,将 margin  设置为 auto ,由于宽高固定,对应方向实现平分,该方法必须盒子有宽高。

实现水平居中,top、bottom不要设值。垂直居中left、right不要设值。

  1. 利用绝对定位,设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 margin-left  和 margin-top  以子元素自己的一半宽高进行负值赋值。该方法必须定宽高
  2. 利用 flex ,最经典最方便的一种了,不用解释,定不定宽高无所谓的。justify-content

           align-items

CSS选择器优先级

(1)CSS选择器都有权重值,权重值越大优先级越高。

    内联样式表的权重值最高,值为1000。

    id选择器的权重值为100。

    类选择器的权值为10。

    类型(元素)选择器的优先级为1。

    通配符选择器的优先级为0。

(2)当权值相等时,后定义的样式表要优于先定义的样式表。

(3)在同一组属性设置中表有**“!important"**规则的优先级最大

伪类

链接伪类选择器

:not(n)匹配非指定元素n的每个元素
:focus匹配获得焦点(光标)的元素
:first-child匹配指定父元素下的第一个子元素
:last-child匹配指定父元素下的最后一个子元素
:nth-​​child(n)匹配指定元素下的第n个子元素
:default匹配标签中的默认元素

 

伪元素

应用场景一: 字体图标

应用场景三: 清除浮动

层次选择器

后代选择器 $("p span")

子选择器 $("parent>child")

同辈选择器 $("prev+next")

同辈选择器 $("prev~siblings")

 

图片懒加载、预加载。

1.图片懒加载,在图片未可视区域加一个滚动条事件,判断图片位置与浏览器顶端和页面的距离, 如果前者小鱼后者, 优先加载

2.使用图片预加载技术, 将当前展示图片的前一张和后一张优先下载

3.使用 csssprite 或者 svgsprite

预加载和懒加载的区别,预加载在什么时间加载合适

预加载是指在页面加载完成之前,提前将所需资源下载,之后使用的时候从缓存中调用; 懒加载是延迟加载, 按照一定的条件或者需求等到满足条件的时候再加载对应的资源 两者主要区别是一个是提前加载, 一个是迟缓甚至不加载。懒加载对服 务器前端有一定的缓解压力作用, 预加载则会增加服务器前端压力。

行内元素、块级元素特点:

块级元素的特点:

①自己独占一行。

② 高度,宽度、外边距以及内边距都可以控制。

③ 宽度默认是容器(父级宽度)的100%。

④ 是一个容器及盒子,里面可以放行内或者块级元素

行内元素的特点:

① 相邻行内元素在一行上,一行可以显示多个。

② 高、宽直接设置是无效的。

③ 默认宽度就是它本身内容的宽度。

④ 行内元素只能容纳文本或其他行内元素。

块级元素: div h1-h6 hr p ul ol table address blockquote dir from menu

行内元素: a br I em img input select span sub sup u textarea

可变元素: button del iframe in

弹性盒子布局属性

flex-direction属性决定主轴的方向(即项目的排列方向)。

Align-item: 属性定义项目在交叉轴上如何对齐。

Justify-content: justify-content属性定义了项目在主轴上的对齐方式。

Flex-wrap: 设置弹性盒子的子元素超出父容器时是否换行

Flex-flow: 是 flex-direction 和 flex-wrap 简写形式

Align-content: 属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

.box {

  flex-direction: row | row-reverse | column | column-reverse;

}

Justify-content: justify-content属性定义了项目在主轴上的对齐方式。

.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

 

Flex-wrap: 设置弹性盒子的子元素超出父容器时是否换行

Flex-flow: 是 flex-direction 和 flex-wrap 简写形式

Align-item: 属性定义项目在交叉轴上如何对齐。

 

Align-content: 属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

怎么实现标签禁用

添加 disabled 属性

Px、em、rem

Px,绝对长度单位, 像素 px 是相对于显示器屏幕分辨率来说的

em 相对长度单位, 相对于当前对象内文本的字体尺寸

em 的值并不是固定的 em 会继承父级元素的字体大小 (参考物是父元素的 font-size)

em 中所有的字体都是相对于父元素的大小决定的

rem``的大小是根据html根目录下的字体大小进行计算的。

当我们改变根目录下的字体大小的时候,下面字体都改变。

rem``不仅可以设置字体的大小,也可以设置元素宽、高等属性。

1em=1rem=16px 在 body 中加入 font-size: 62.5% 这样直接就是原 来的 px 数值除以 10 加上 em 就可

请简述媒体查询

媒体查询扩展了 media 属性, 就是根据不同的媒体类型设置不同的 css 样式, 达到自适应的目的。

Rem 缺点

比如: 小说网站, 屏幕越小的移动设备如果用了 rem 肯定文字就越小, 就会导致看文章的时候特别费眼

 

实现圣杯布局和双飞翼布局(经典三分栏布局)

圣杯布局和双飞翼布局的目的:

三栏布局,中间一栏最先加载和渲染(内容最重要,这就是为什么还需要了解这种布局的原因)。两侧内容固定,中间内容随着宽度自适应。一般用于 PC 网页。

圣杯布局和双飞翼布局的技术总结:

1.使用 float  布局。

2.防止中间内容被两侧覆盖,圣杯布局用 padding ,给父盒子设置padding值。双飞翼布局用 margin ,给中间盒子设置margin。两侧使用 margin 负值,将左侧部分与右侧部分合理分配。

上述代码中 margin-left: -100%  相对的是父元素的 content宽度,即不包含 paddig 、 border  的宽度。

其实以上问题需要掌握 margin 负值问题 即可很好理解。

juejin.cn/post/706158…

外边距重叠

多个相邻 (兄弟或者父子关系) 普通流的块元素垂直方向 marigin 会重 叠折叠的结果为: 两个相邻的外边距都是正数时, 折叠结果是它们两者之间较大的值。两个相邻的外边距都是负数时, 折叠结果是两者绝对值的较大值。 两个外 边距一正一负时, 折叠结果是两者的相加的和。

margin负值问题

·  margin-top 元素自身会向上移动,同时会影响下方的元素会向上移动;

·  margin-botom 元素自身不会位移,但是会减少自身供css读取的高度,从而影响下方的元素会向上移动。

·  margin-left 元素自身会向左移动,同时会影响其它元素;

·  margin-right 元素自身不会位移,但是会减少自身供css读取的宽度,从而影响右侧的元素会向左移动;。

 

Src和href区别

src``和href的作用都是用于请求资源。

区别:

1.``请求资源类型不同

href``,超文本引用,用于建立文档与资源的联系,常用的有:link、a。

src``,将其所指向的资源下载并应用到当前页面(请求到的资源替换当前内容),常见的有script、img。

2.``作用结果不同

href``,用于文档与资源之间确立联系。

src``,请求到的资源替换当前内容。

3.``浏览器的解析不同

href``,将资源解析成css文件,并行加载请求资源,不会阻塞对当前文档的处理。

src``,会暂停其他资源的处理,直到该资源加载、解析和执行完毕,将其所指向资源应用到当前内容。这也是为什么把js文件放在底部而不是头部的原因。

HTML5





新增语义化标签

新增表单类型

表单元素 表单属性 表单事件

多媒体标签

HTML5 中的一些有趣的新特性:

· 用于绘画的 canvas 元素

· 用于媒介回放的 video 和 audio 元素

· 对本地离线存储的更好的支持

· 新的特殊内容元素,比如 article、footer、header、nav、section

· 新的表单控件,比如 calendar、date、time、email、url、search

 

Html5





语义化标签优点: 1.提升可访问性 2.seo(搜索引擎优化) 3.结构清晰, 利于维护

Header ``页面头部 main 页面主要内容 footer 页面底部

Nav ``导航栏 aside 侧边栏 article 加载页面一块独立内容

Section ``相 当 于 div

figure ``加 载 独 立 内 容 ( 上 图 下 字 )

figcaption figure ``的标题

Hgroup ``标题组合标签

mark ``高亮显示

dialog ``加载对话框标签 (必须配合 open 属性)

Embed ``加载插件的标签 video 加载视频 audio 加载音频 (支持格式

ogg``, mp3, wav)

BFC(块级格式上下文)

BFC是一个完全独立的空间(布局环境),让空间里的子元素不会影响到外面的布局。

触发BFC

• overflow: hidden

 • display: inline-block

 • position: absolute • position: fixed

 • display: table-cell • display: flex

BFC规则

 • BFC就是一个块级元素,块级元素会在垂直方向一个接一个的排列

 • BFC就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签

• 垂直方向的距离由margin决定, 属于同一个BFC的两个相邻的标签外边距会发生重叠

• 计算BFC的高度时,浮动元素也参与计算

 BFC解决的问题

使用Float脱离文档流,高度塌陷  Margin边距重叠

 

CSS

Css3


边框``:

border-radios ``添加圆角边框

border-shadow``: 给框添加阴影 (水平位移, 垂直位移, 模糊半径, 阴影尺寸, 阴影颜色, insetr (内/外部阴影))

border-image``: 设置边框图像

border-image-source ``边框图片的路径

border-image-slice ``图片边框向内偏移border-image-width 图片边框的宽度

border-image-outset ``边框图像区域超出边框的量

border-image-repeat ``图像边框是否平铺 (repeat 平铺 round 铺满stretch 拉伸)

背景``:

Background-size ``背景图片尺寸

Background-origin ``规定 background-position 属性相对于什么位置定

Background-clip ``规定背景的绘制区域 (padding-box, border-box, content-box)

渐变:

Linear-gradient () ``线性渐变Radial-gradient () 径向渐变文本效果:

Word-break``: 定义如何换行

Word-wrap``: 允许长的内容可以自动换行

Text-overflow``: 指定当文本溢出包含它的元素, 应该干啥

Text-shadow``: 文字阴影 (水平位移, 垂直位移, 模糊半径, 阴影颜色) 转换:

Transform ``应用于 2D3D 转换, 可以将元素旋转, 缩放, 移动, 倾斜Transform-origin 可以更改元素转换的位置, (改变 xyz 轴) Transform-style 指定嵌套元素怎么样在三位空间中呈现

2D ``转换方法:

rotate ``旋转 translate (x, y) 指定元素在二维空间的位移 scale (n)

定义缩放转换3D 转换方法:

Perspective`` (n) ``为 3D 转换 translate rotate scale

过渡:

Transition`` -proprety ``过渡属性名

Transition-duration ``完成过渡效果需要花费的时间Transition-timing-function 指定切换效果的速度Transition-delay 指定什么时候开始切换效果

动画: animation

Animation-name ``为@keyframes 动画名称animation-duration 动画需要花费的时间animation-timing-function 动画如何完成一个周期animation-delay 动画启动前的延迟间隔animation-iteration-count 动画播放次数animation-direction 是否轮流反向播放动画

盒模型

IE 盒模型:属性 widthheight 包含 contentborder 和 padding,指的是 content + padding + border

W3C 标准盒模型:属性 width ,height 只包含内容 content,不包含 border 和 padding 。

display 都有哪些属性

 

Js

Js基本数据类型

在 JS 中共有 8  种基础的数据类型,分别为: Undefined 、 Null 、 Boolean 、 Number 、 String 、 Object 、 Symbol 、 BigInt 。

我们经常使用的的类型如:arrayfunction 都属于复杂数据类型 Object

其中 Symbol  和 BigInt  是 ES6 新增的数据类型,可能会被单独问:

Symbol 代表独一无二的值,最大的用法是用来定义对象的唯一属性名。

BigInt 可以表示任意大小的整数。

值类型是直接存储在**栈(stack)**中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

引用类型存储在**堆(heap)**中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;

值类型和引用类型分别有哪些?

基本的值类型有 :   undefinedBooleanNumberStringSymbol

引用类型有:   Object

特殊的引用类型: null,指针指向空地址。

特殊的引用类型: function,不用于储存数据,所以没有复制,拷贝函数一说。

 

JavaScript属于什么类型的语言?

·        使用之前就需要确认其变量类型的称为 静态语言

·        在运行过程中需要检查数据类型的语言称为 动态语言

·        支持隐式类型转换的语言称为 弱类型语言,反之为 强类型语言

·        JavaScript 属于 动态语言弱类型语言

什么是虚值和真值?分别有哪些?

简单的来说 虚值 就是 在转换为布尔值时 变为 false 的值,变为 true 的值则为 真值 。

虚值(Falsy)

·        长度为 0 的字符串

·        数字 0

·        false

·        undefined

·        null

·        NaN

真值(Truthy)

·        空数组

·        空对象

·        其他

 

函数作用域

比如在函数中定义一个变量,只能在函数这个独立作用域中使用(也就是封闭的盒子)。只要跳出这个作用域,就找不到该变量了。

作用域链的理解?

   作用域分为 全局 局部 块级

   平时开发过程中 作用域存在嵌套, 变量的访问的链式作用域结构 称之为作用域链

   变量的访问规则: 就近 优先访问自己的作用域链,如果没有 一层层向外访问

如何判断一个数不是NaN

1.NaN 非数字,但是用 typeof 检测是 number 类型。利用 NaN 的定义,用 typeof 判断是否为 number 类型并且判断是否满足 isnan。

2.利用NaN 是唯一一个不等于任何自身的特点 n! = =n

3.利用 ES6 中提供的 Object.is()方法 (判断两个值是否相等) n = =nan

Js 中 null 与 undefined

相同点:用 if 判断时, 两者都会被转换成 false

不同点:1.number 转换的值不同 number (null) 为0,number (undefined) 为 NaN。

TypeOf(null) = object

TypeOf(undefined) = undefined

1.      Null 表示一个值被定义了,但是这个值是空值。Undefined 变量声明但未赋值。

ES6新特性

const 和 let、模板字符串、箭头函数、 函数的参数默认值、对象和数组解构、for...of 和 for...in、 ES6 中的类

模板字符串

ES6 引入新的声明字符串的方式

内容中可以直接出现换行符

变量拼接

函数的参数默认值

形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)

与解构赋值结合

扩展运算符的运用:

数组的合并

数组的克隆

将伪数组转为真正的数组

ES6

  1. 新增symbol类型 表示独一无二的值,用来定义独一无二的对象属性名;

  2. const/let 都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,也就是不存在变量提升。(const一般用于声明常量);

  3. 变量的解构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(...rest);

  4. 模板字符串(${data});

  5. 扩展运算符(数组、对象);;

  6. 箭头函数;

 7. Set和Map数据结构;

  1. Proxy/Reflect;

  2. Promise;

  3. async函数;

  4. Class;

  5. Module语法(import/export)

13.for...of 和 for...in

 

var let const的区别

1、变量提升:

var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined

let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错

2、暂时性死区:

    var不存在暂时性死区

    let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量

3、块级作用域:

    var不存在块级作用域

    let和const存在块级作用域

4、重复声明:

    var允许重复声明变量

    let和const在同一作用域不允许重复声明变量

5、修改声明的变量:

    var和let可以

    const声明一个只读的常量。一旦声明,常量的值就不能改变

五、使用

 

能用const的情况尽量使用const,其他情况下大多数使用let,避免使用var

内存回收机制

内存回收机制就是不在用到的内存空间,系统会自动进行清理出空间提供给其他程序使用。

js中内存的分配与回收 是自动完成的! 怎么做到的???

注意点: 不是所有的内存都会被立刻回收,回收机制有两种, (满足了回收机制,被确认是垃圾,才会被回收)

   (1) 引用计数法(ie)

       引用计数的回收  就是看 这个内存空间的引用数, 一旦没有任何变量指向它 说明这块内存就不在被需要了(垃圾)  就会被回收

      

       循环引用 会导致内存的引用数不为0 总有变量指向这块内存 不认为它是垃圾 不会回收这块内存, 这块内存被浪费(内存泄露)

   (2) 标记清除法(主流浏览器  谷歌 火狐)

       回收策略: 将不再使用的对象 定义成 '无法到达的对象' 就要被回收

       1. 从根部(js中的全局对象)出发, 定时去扫描内存中的对象

       2. 凡是从根部能够到达的对象, 都是还需要使用的, 但是如果无法从根部出发找到, 被标记成不再使用,就会被回收!!

什么是闭包

而且函数执行完毕之后,这个独立作用域或(封闭的盒子)就会删除。有一种情况下这个封闭的盒子是不会删除的,那就是“闭包”

在一个函数里边我们再声明一个函数,内部函数可以访问外部函数作用域的变量,而外部的函数不能获取到内部函数的作用域变量。

闭包应用: 缓存数据 实现数据私有

闭包的优点

1:变量长期驻扎在内存中;

2:避免全局变量的污染;

3:私有成员的存在 ;

缺点: 会造成内存泄露

闭包经典使用场景之一

闭包经典使用场景之一:通过循环给页面上多个dom节点绑定事件。

<ul>
  <li>编号1,点击我请弹出1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
for(var i = 0; i  <  list.length; i ++ ) {
  list[i].onclick = function() {
    alert(i)
  }
}

结果是点击每一项都弹出5 。原因是onclick事件是异步触发的,当事件被触发时,for循环早已结束,此时变量i的值已经是5!故当onclick事件顺着作用域链从内向外查找变量i时,找到的值总是5。

var list = document.getElementsByTagName('li')
for(var i = 0; i  <  list.length; i ++ ) {
  list[i].addEventListener('click', function(i){
    return function() {
      alert(i + 1)
      console.log(i + 1)
    }
  }(i), true)
}

在闭包作用下,定义事件函数的时候,每次循环的i值都封闭起来,这样在函数执行时,会查找定义时的作用域链,这个作用域链里的i值是在每次循环中都被保留的,因此点击不同的li会alert出不同编号。

事件委托是什么?

JS 高程上讲: 事件委托就是利用事件冒泡, 只制定一个事件处理程序, 就可以管理某一类型的所有事件。 事件委托, 称事件代理, 是 js 中很常用的绑定事件的技巧, 事件委托就是把原本需要绑定在子元素的响应事件委托给父元素, 让父元素担当事 件监听的职务, 事件委托的原理是 DOM 元素的事件冒泡

什么是事件冒泡

一个事件触发后, 会在子元素和父元素之间传播, 这种传播分为三个阶 段, 捕获阶段 (从 window 对象传导到目标节点 (从外到里), 这个阶段不会 响应任何事件), 目标阶段, (在目标节点上触发), 冒泡阶段 (从目标节 点传导回 window 对象 (从里到外)), 事件委托/事件代理就是利用事件 冒泡的机制把里层需要响应的事件绑定到外层    

要掌握 cookie,localStorage 和 sessionStorage。

1、cookie

本身用于浏览器和 server 通讯。

被“借用”到本地存储来的。

可用 document.cookie = '...' 来修改。

其缺点:

存储大小限制为 4KB。

http 请求时需要发送到服务端,增加请求数量。

只能用 document.cookie = '...' 来修改,太过简陋。

2、localStorage 和 sessionStorage

HTML5 专门为存储来设计的,最大可存 5M。

API 简单易用, setItem getItem。

不会随着 http 请求被发送到服务端。

它们的区别:

localStorage 数据会永久存储,除非代码删除或手动删除。

sessionStorage 数据只存在于当前会话,浏览器关闭则清空。

一般用 localStorage 会多一些。

Localstorage

存储token、获得token、清空token

sessionStorage

只有携带的skuNum以及sessionStorage中有skuInfo数据, 才能查看添加购物车成功的界面

产品信息的数据【比较复杂:skuInfo】,通过会话存储(不持久化,会话结束数据在消失)

sessionStorage.setItem("SKUINFO", JSON.stringify(this.skuInfo));

return JSON.parse(sessionStorage.getItem("SKUINFO"));

 

 

我的预约

会议室预约

会议室管理

主页

管理员批准

原型、原型链

引用类型:Object、Array、Function、Date、RegExp。这里我姑且称 proto 为隐式原型

1、 引用类型,都具有对象特性,即可自由扩展属性。

![文本, 信件

描述已自动生成]()

2、引用类型,都有一个隐式原型 proto 属性,属性值是一个普通的对象。

3、引用类型,隐式原型 proto 的属性值指向它的构造函数的显式原型 prototype 属性值。

![文本, 信件

描述已自动生成]()

4、当你试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么它会去它的隐式原型 proto(也就是它的构造函数的显式原型 prototype)中寻找。

原型对象(构造函数的显式原型)(即Person.prototype)的constructor指向构造函数本身

原型、原型链得意义:当相同的属性、方法越多,原型、原型链的意义越大。

juejin.cn/post/693449…

www.cnblogs.com/MikeChow/p/…

对象的属性查找原则:
1.首先在对象自身查找是否有该属性,如果有,返回结果

2.如果没有,就去对象的原型上查找,如果有,返回结果

3.如果没有,就沿着原型链往上查找,一直找到Object.prototype,如果有,返回结果

4.如果没有返回undefined

 //如果我查一个对象的某一个属性,该怎么查呢?

 //如果A对象有一个属性B,在A本身找不到这个属性的话,该怎么做?

 //比如说A是继承C的,如果A里没有这个属性的话。会不会去C里找?

 //C里也找不到呢?会不会在别的地方找?

 //如果最终找不到,会报错吗?

 //指向null还是undefined

 //会返回什么?面试官答:会返回undefined。

Promise

JavaScript后端开发要借助node.js(运行环境)
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise对象有以下两个特点。

1)对象的状态不受外界影响。

2)一旦状态改变,就不会再变。(Promise只以第一次为准,第一次成功就永久为fulfilled,第一次失败就永远状态为rejected)

基本用法

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise中有throw的话,就相当于执行了reject。这就要使用try catch

juejin.cn/post/699459…

我们用promise解决什么问题?

1.      回调地狱, 代码难以维护, 常常第一个的函数的输出是第二个函数的 输入这种现象

var sayhello = function (order, callback) {

       setTimeout(function () {

    console.log(order);

    callback();

  }, 1000);

}

sayhello("first", function () {

  sayhello("second", function () {

    sayhello("third", function () {

      console.log("end");

    });

  });

});

2.      promise 可以支持多并发的请求, 获取并发请求中的数blog.csdn.net/djh052900/a…

 

3.      promise链式调用 场景:我发请求获取学生id, 还需要根据学生id获取学生成绩,

then方法本身会返回一个新的Promise对象

如何实现 Promise.all  Promise.race??

 

   等待数组中的所有promise 都完成 才会执行 Promise.all的成功函数

   Promise.all([p1, p2, p3]).then((values) => { ... })

 

  

   哪个promise最先完成, 就会执行Promise.race 的成功函数

   Promise.race([p1, p2, p3]).then((value) => { ... })

还需要根据学生成绩获取他的排名  .then中可以继续返回promise 

等下一个.then中的回调函数去处理

如果想要其中一个请求出错了但是不返回结果怎么办

 

allSettled

·        把每一个Promise的结果,集合成数组,返回

any

·        如果有一个Promise成功,则返回这个成功结果

·        如果所有Promise都失败,则报错

 

请简述async/await区别

Async 就是 Promise 的语法糖,异步操作方法前加一个 await 关键字,意思就是等一下, 执行完了再继续走,

注意: await 只能在 async 函数中运行,否则会报错。

Promise 如果返回的是一个错误的结果, 如果没有做异常处理, 就会报错, 所以用 try..catch 捕获一下异常就可以了。

JS的new操作符做了哪些事?

new 操作符新建了一个空对象,这个对象原型指向构造函数的 prototype,执行构造函数后返回这个对象

改变函数内部this指向

![文本, 信件

描述已自动生成]()

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。call() 可以改变this的指向。

我们会了 call 的实现之后,apply 就变得很简单了,他们没有任何区别,除了传参方式。

相同点:

都可以改变函数内部的this指向. call 和 apply  会调用函数, 并且改变函数内部this指向.

区别点:

call 和 apply 传递的参数不一样, call 传递参数 aru1, aru2..形式  apply 必须数组形式[arg]

bind  不会调用函数, 可以改变函数内部this指向.

主要应用场景: 

call 经常做继承.

apply 经常跟数组有关系.  比如借助于数学对象实现数组最大值最小值

bind  在不调用函数情况下,但是还想改变this指向. 比如改变定时器内部的

原生js

原生js:就是不适用框架,开发js代码

在传统的JavaScript 开发中,查找DOM 往往是开发人员遇到的第一个头疼的问题,原生的JavaScrip所提供的DOM 选择方法并不多,仅仅局限于通过tag.name.id 等方式来查找,这显然是远不够的,如果想要进行更为精确的选择不得不使用看起来非常繁琐的正则表达式,或者使用某个库。事实上现在所有的浏览器厂商都提供了queryelector 和guerySelectorAll 这两个方法的支持,甚至就连微软也派出了E8作为支持这一特性的代表,queryelector和guerySelectorAll 作为查找DOM 的又一途径,极大地方便了开发者。使用它们,你可以像使用CSS选择器一样快速地查找到你需要的节点。

1 document.querySelector("#test"):

2 document.querySelectorAll("#test")[0]:

3 document.querySelector("div.test>p:first-child");

4 document.querySelectorAll("div.test>p:first-child")[0];

queryelector和 guerySelectorAll 的区别在于 queryelector 用来获取第一个素,而guerySelectorAll 可以获取多元素。queryelector将返回匹配到的第一个元素,如果没有匹配的元素则返回 Null。guerySelectorAll返回一个包含匹配到的元素的数组,如果没有匹配的元素则返回的数组为空

事件冒泡:

事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。可以想象把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。

DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

事件捕获:

事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定),与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。

 

事件冒泡、捕获(委托)

事件冒泡指在在一个对象上触发某类事件,如果此对象绑定了事件,就会触发事件,如果没有,就会向这个对象的父级对象传播,最终父级对象触发了事件。

事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。 event.stopPropagation() 或者 ie下的方法 event.cancelBubble = true; //阻止事件冒泡

 

Js将字符串转换为数组

使用 .split(''): split() 是一种字符串方法,可将字符串拆分为具有模式的有序列表的数组。这是一种 ES6 方法,是完成工作的最干净的方法。

使用扩展语法 ([…str]) 这是 ES2015 的特性,它使转换变得非常容易。

Array.from(str) from() 方法从可迭代或类似数组的对象创建一个新的、浅拷贝的 Array 实例。

 Object.assign([], str) 深拷贝

类数组

如果一个对象有 length 属性值,则它就是类数组

这在 DOM 中甚为常见,如各种元素检索 API 返回的都是类数组,如 document.getElementsByTagName,document.querySelectorAll 等等。除了 DOM API 中,常见的 function 中的 arguments 也是类数组

For…in For…of

for in更适合遍历对象,当然也可以遍历数组,但是会存在一些问题。

for…in遍历的index为字符串型数字,不能直接进行几何运算

遍历顺序有可能不是按照实际数组的内部顺序

用for in会遍历数组所有的可枚举属性,包括原型,如果不想遍历原型方法和属性的话,可以在循环内部判断一下,使用hasOwnProperty()方法可以判断某属性是不是该对象的实例属性

for of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象(iterator)的集合,但是不能遍历对象

for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值

for in总是得到对象的key或数组、字符串的下标

for of总是得到对象的value或数组、字符串的值

for...in 和 for...of有什么区别

·        for...in 遍历得到 key

·        for...of 遍历得到 value

for...in

可以用在可枚举的数据,如:

·        对象

·        数组

·        字符串

for...of用于可迭代的数据,如:

·        数组

·        字符串

·        Map

·        Set

 

 

数据类型的判断

• typeof:能判断所有值类型,函数。不可对 null、对象、数组进行精确判断,因为都返回 object 。

• instanceof:能判断对象类型,不能判断基本数据类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。

Set和Map

  1. 存储方式:Set是一组唯一值的集合,每个值只能出现一次;而Map是键值对的集合,每个键对应一个值。 2. 值的类型:Set中的值可以是任意类型的,包括基本类型和对象引用;而Map中的键和值可以是任意类型的,包括基本类型和对象引用。

  2. 迭代顺序:Set按照插入顺序进行迭代,即元素的顺序与插入的顺序一致;而Map按照插入顺序进行迭代,即键值对的顺序与插入的顺序一致。

  3. 值的唯一性:Set中的值是唯一的,不会重复;而Map中的键是唯一的,每个键只能对应一个值。

  4. 大小和性能:Set和Map的大小可以动态增长,可以根据需要添加或删除元素。在查找元素的操作上,Set使用严格相等(===)进行匹配,而Map使用键进行匹配,因此在查找元素的性能上,Map通常比Set更好。

 

nodejs

垃圾回收机制

对称加密,非对称加密

菜鸟教程

自己在github上下载过项目,安装下来感受过他的结构。

Mysql

安装Mysql

可视化工具

基本的增删改查、一些Like字句、排序、分组、关键字

Vite、webpack

Jquery

less的特性有哪些

1.less可以进行嵌套

2. Less 中的变量十分强大,可化万物,值得一提的是,其变量是常量 ,所以只能定义一次,不能重复使用。

以 @ 开头 定义变量,并且使用时 直接 键入 @名称

3.& (and)的妙用,代表上一层选择器的名称

9.媒体查询,less可以让媒体查询的写法更加便捷直观

sass的基本使用

嵌套规则

2、父选择器&

3、属性嵌套

4、注释/ /与//

5、运算

请掌握两种以上数组去重方式

使用 indexof () 方法

使用 lastindexof () 方法 和 indexof 方法一样 indexof 从头部开始匹配 lastindexof 从尾部匹配

ES6 的 set 结构 set 不接受重复数据

使用 sort 方法先将原数组排序, 然后与相邻的比较, 如果不同则存入新数组

使用 filiter 和 indexof 方法 使用 ES6 的 set 和扩展运算符 使用 set 和 Array.from () 方法 array.from 可以将 set 结构转 成数组 用 splice 和双层循环 使用 includes 方法

深拷贝

深拷贝: 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象(新旧对象不共享同一块内存),且修改新对象不会影响原对象(深拷贝采用了在堆内存中申请新的空间来存储数据,这样每个可以避免指针悬挂)

浅拷贝

浅拷贝: 如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址(新旧对象共享同一块内存),所以如果其中一个对象改变了这个地址,就会影响到另一个对象(只是拷贝了指针,使得两个指针指向同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃);

浅拷贝的实现

注意:当拷贝对象只有一层的时候,是深拷贝

展开运算符 ... 实现浅拷贝**

bject.assign() 实现浅拷贝**

Object.assign()  方法将所有可枚举Object.propertyIsEnumerable() 返回 true)的自有Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象

Array.prototype.concat() 实现浅拷贝**

let arr2 = arr1.concat([]);

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

Array.prototype.slice()实现浅拷贝**

let arr2 = arr1.slice();

slice()  方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

computed: {

    ...mapState({

      userName: (state) => state.user.userInfo.name,

    }),

  },

![文本

描述已自动生成]()

//  JSON.parse(JSON.stringify()) 实现深拷贝 Array

jQuery.extend()方法**

手写递归方法

![图形用户界面, 应用程序

描述已自动生成]()

JSON.parse/JSON.stringify

indexOf()  方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回 -1。

JSON.stringify

应用场景:

//判断数组是否包含某对象

//判断两数组/对象是否相等

localStorage/sessionStorage默认只能存储字符串,而实际开发中,我们往往需要存储的数据多为对象类型,那么这里我们就可以在存储时利用json.stringify()将对象转为字符串,而在取缓存时,只需配合json.parse()转回对象即可

实现对象深拷贝

实际开发中,如果怕影响原数据,我们常深拷贝出一份数据做任意操作,其实使用JSON.stringify()与JSON.parse()来实现深拷贝是很不错的选择。

let arr = [1,2,3]; JSON.stringify(arr);//'[1,2,3]'

arr.toString();//1,2,3

JSON.stringify()的受众更多是对象,而toString()虽然可以将数组转为字符串,但并不能对{name:‘天子笑’}这类对象实现你想要的操作,它的受众更多是数字。

为什么说js是弱类型语言?

弱类型语言实现相对于强类型语言来说的,在强类型语言中, 变量类型有多种,比如 int float char Boolean 不同类型相互转换有时需要强制转换,而jacascript 只有一种类型var, 为变量赋值时会自动判断类型并转换,所以是弱类型语言。

echarts

图表及图表组合

For 图标

描述已自动生成  map 图片包含 文本

描述已自动生成

For 遍历对象自身的和继承可枚举的属性,也就是说会包括哪些原型链上的属性

| | Item:每一项 | | -------- |  | | -------------------------- |

Map 方法不会对空数组进行检测, map 会返回一个新数组,不会对原数组产生影响![表格

描述已自动生成]()

This指向

在JavaScript 中, this 通常指向的是我们正在执行的函数本身, 或者是指向该函数所属的对象。

全局的this → 指向的是 Window

对象中的this → 指向其本身

事件中this → 指向事件对象

 

this 永远指向最后调用它的那个对象****

this指向?

  (1) 普通函数  this => window; js严格模式 指向undefined

  (2) 方法调用模式  obj.fn()  this => 调用者obj

  (3) 构造函数模式  new Person()  this => 实例

  (4) 借调模式 call  apply  bind   this  =>  指向第一个参数

  (5) 箭头函数没有this => 上一层作用域的this


怎么改变 this 的指向

  • 使用 ES6 的箭头函数

箭头函数的 this 始终指向函数定义时的 this,而非执行时。 ,箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

  • 在函数内部使用 _this = this
  • 使用 apply、call、bind
  • new 实例化一个对象

 

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。call() 可以改变this的指向。

我们会了 call 的实现之后,apply 就变得很简单了,他们没有任何区别,除了传参方式。

相同点:

都可以改变函数内部的this指向. call 和 apply  会调用函数, 并且改变函数内部this指向.

区别点:

call 和 apply 传递的参数不一样, call 传递参数 aru1, aru2..形式  apply 必须数组形式[arg]

bind  不会调用函数, 可以改变函数内部this指向.

主要应用场景: 

call 经常做继承.

apply 经常跟数组有关系.  比如借助于数学对象实现数组最大值最小值

bind  在不调用函数情况下,但是还想改变this指向. 比如改变定时器内部的this

箭头函数和普通函数区别

箭头函数是匿名函数, 不能作为构造函数, 不能使用new

箭头函数不能绑定 arguments, 要用rest 参数解决

箭头函数没有原型属性

箭头函数的 this 永远指向其上下文的this,

箭头函数不能绑定this, 会捕获其所在的上下文的this 值, 作为自己的this 值

什么是js内存泄漏

内存泄漏是指一块被分配的内存既不能使用又不能回收, 直到浏览器进程结束

释放内存的方法: 赋值为null

预加载和懒加载的区别,预加载在什么时间加载合适

预加载是指在页面加载完成之前,提前将所需资源下载,之后使用

的时候从缓存中调用; 懒加载是延迟加载, 按照一定的条件或者需求等到满足条件的时候再加载对应的资源

两者主要区别是一个是提前加载, 一个是迟缓甚至不加载。懒加载对服 务器前端有一定的缓解压力作用, 预加载则会增加服务器前端压力。

1.图片懒加载,在图片未可视区域加一个滚动条事件,判断图片位置与浏览器顶端和页面的距离, 如果前者小鱼后者, 优先加载

2.使用图片预加载技术, 将当前展示图片的前一张和后一张优先下载

3.使用 csssprite 或者 svgsprite

Js

函数节流是指一定时间内 js 方法只执行一次。

函数防抖是指频繁触发的情况下, 只有足够的空闲时间, 才执行代码一次

函数节流是声明一个变量当标志位, 记录当前代码是否在执行, 如果正在执行, 取消这次方法执行, 直接return, 如果空闲, 正常触发方法执行

函数防抖是需要一个计时器来辅助实现, 延迟执行需要执行的代码, 如果方法多次触发, 把上次记录的延迟执行代码用 cleartimeout 清除掉, 重新开始, 如果计时完毕, 没有方法来访问触发, 则执行代码

防抖节流的应用场景

判断是否为数组?

  (1) Object.prototype.toString.call(数据)  '[object Array]'

 

  (2) Array.isArray(数组)  true

宏任务

(macro)task(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个 (macro)task 执行结束后,在下一个 (macro)task 执行开始前,对页面进行重新渲染,流程如下:

(macro)task->渲染->(macro)task->...

(macro)task主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)

async函数中在await之前的代码是立即执行的,async await 本身就是promise+generator的语法糖。所以await后面的代码是microtask。所以对于本题中的。

微任务

microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。

所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)

Eventloop事件循环

 

 

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

流程图如下:

![图示

描述已自动生成]()

同步和异步的区别

同步: 同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。

异步: 将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。

虚拟 dom 和真实 dom 的区别

  • 虚拟 DOM 不会进行排版与重绘操作 
  • 虚拟 DOM 就是把真实 DOM 转换为 Javascript 代码
  • 虚拟 DOM 进行频繁修改,然后一次性比较并修改真实 DOM 中需要改的部分,最后并在真实 DOM 中进行排版与重绘,减少过多 DOM 节点排版与重绘损耗

Vue

 请简述你对vue的理解

Vue 是一套构建用户界面的渐进式的自底向上增量开发的 MVVM 框架, 核心是关注视图层,vue 的核心是为了解决数据的绑定问题,为了开发大型单页面应用和组件化, 所以vue 的核心思想是数据驱动和组件化

Mvvm与mvc的区别

Mvc 模型视图控制器, 视图是可以直接访问模型, 所以, 视图里面会包含模型信息, mvc 关注的是模型不变, 所以, 在mvc 中, 模型不依赖视图, 但是视图依赖模型

Mvvm 模型 视图 和 vm vm 是作为模型和视图的桥梁, 当模型层数据改变, vm 会检测到并通知视图层进行相应的修改

mvvm框架和其它框架的区别是什么?(jquery)哪些场景适合?

Mvvm 和其他框架的区别是 vue 数据驱动 通过数据来显示视图而不是节点操作

适用于数据操作比较多的场景。什么叫数据操作比较多的场景?

MVVM详解:

1.  View层:

视图层,在前端里就是我们常说的DOM层,主要作用是给用户展示各种信息;

2.  Model层:

数据层(逻辑层),数据可能是我们自定义的数据,或者是从网络请求下来的数据;

3.  ViewModel层:

视图模型层,是View层和Model层沟通的桥梁;一方面它实现了数据绑定(Data Binding),将Model的改变实时反应到View中;另一方面它实现了DOM监听,当DOM发生改变可以对应改变数据(Data)(View发生改变也会反映到Model中)

怎样理解 Vue 的单向数据流

数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

Vue常见的修饰符

.lazy、.trim、.stop、.prevent、.capture、.self、.once

修饰符: .lazy 改变后触发, 光标离开input 输入框的时候值才会改变.

number 将输出字符串转为 number 类型

.trim 自动过滤用户输入的首尾空格

事件修饰符:

事件修饰符:

.stop阻止点击事件冒泡,相当于原生js中的event.stopPropagation()

![文本

描述已自动生成]()

.prevent防止执行预设的行为,相当于原生js 中event.preventDefault()

.capture添加事件侦听器时使用事件捕获模式,就是谁有该事件修饰符,

就先触发谁

 

 

![文本

描述已自动生成]()

 

.self 只会触发自己范围内的事件, 不包括子元素

.once 只执行一次

![图形用户界面, 应用程序

描述已自动生成]()

键盘修饰符:

.enter 回车键          .tab 制表键              .esc 返回键                                 .space 空格键

.up 向上键                .down 向下键        .left 向左建     .right 向右键系统修饰符: .ctrl .alt.shift.meta

 

Vue 图标

低可信度描述已自动生成   key 卡通人物

低可信度描述已自动生成

Key 值的存在保证了唯一性, Vue 在执行时, 会对节点进行检查, 如果没有key 值, 那么vue 检查到这里有dom 节点, 就会对内容清空并赋新值, 如果有key 值存在, 那么会对新老节点进行对比, 比较两者key 是否相同,进行调换位置或删除操作

什么是computed?

计算属性是用来声明式的描述一个值依赖了其他的值, 当它依赖的这个值发生改变时, 就更新DOM

每个计算属性都包括一个getter 和setter,读取时触发getter,修改时触发 setter

Watch请简述

Watch 的作用是监控一个值的变化,并调用因为变化需要执行的方法

Watch 监听的是在 data 中定义的变量,当该变量变化时,会触发 watch 中的方法。

Computed(计算属性)与 watch 区别

Computed watch区别就是 computed 的缓存功能,当无关数据改变时, 不会重新计算,直接使用缓存中的值。

Watch与Computed的区别

  • watch中的函数是不需要调用的,computed内部的函数调用的时候不需要加()
  • watch(属性监听),监听的是属性的变化,而computed(计算属性),是通过计算而得来的数据
  • watch需要在数据变化时执行异步或开销较大的操作时使用,而对于任何复杂逻辑或一个数据属性,在它所依赖的属性发生变化时,也要发生变化,这种情况下,我们最好使用计算属性computed。
  • computed 属性的结果会被缓存,且computed中的函数必须用return返回最终的结果
  • watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;

Watch与Computed的使用场景

·        computed

    • 当一个属性受多个属性影响的时候就需要用到computed
    • 最典型的例子: 购物车商品结算的时候

·        watch

    • 当一条数据影响多条数据的时候就需要用watch
    • 搜索数据

·        总结:

    • 一个值受其他值的影响,用computed
    • 一个值将时刻影响其他值,用watch

watchcomputed 区别和使用场景

对于Computed:

  • 它支持缓存,只有依赖的数据发生了变化,才会重新计算
  • 不支持异步,当 Computed 中有异步操作时,无法监听数据的变化
  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用 computed
  • 如果 computed 属性的属性值是函数,那么默认使用 get 方法,函数的返回值就是属性的属性值;在 computed 中,属性有一个 get 方法和一个 set 方法,当数据发生变化时,会调用 set 方法。

对于Watch:

  • 它不支持缓存,当一个属性发生变化时,它就会触发相应的操作
  • 支持异步监听
  • 监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值
  • 监听数据必须是 data 中声明的或者父组件传递过来的 props 中的数据,当发生变化时,会触发其他操作
  • 函数有两个的参数:
    • immediate:组件加载立即触发回调函数
    • deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。

 

computed与methods的区别

1、computed是属性调用,methods是方法调用

2、computed有缓存功能,多次使用时,该属性只会触发一次调用,而methods是使用一次就触发一次

每个计算属性其实都包含一个getter和setter

![文本

描述已自动生成]()

Vuex是什么?怎么使用?在什么场景下使用?


Vuex 是一个专为 vue.js 应用程序开发的状态管理模式,通过创建一个集中的数据存储, 方便程序中的所有组件进行访问, 简单来说 vuex 就是vue 的状态管理工具

 

Vuex 有五个属性 state getters mutations actions   modules State 就是数据源存放地,对应一般vue 对象的data,state 里面存放的数据是响应式的, state 数据发生改变, 对应这个数据的组件也会发生改变 用this.$store.state.xxx 调用

Getters 相当于 store 的计算属性, 主要是对 state 中数据的过滤, 用this.$store.getters.xxx 调用

![文本, 信件

描述已自动生成]()

 

什么是modules

当项目庞大,状态非常多时,可以采用模块化管理模式Vuex 允许我们将 store 分割成模块(``module``)。每个模块拥有自己的 statemutationactiongetter

Vue中路由跳转方式?

![文本, 信件

描述已自动生成]()

Vue跨域解决方式

![文本, 信件

描述已自动生成]()

Vue生命周期

vue 的生命周期就是 vue 实例创建到实例销毁的过程。期间会有 8 个钩子函数的调用。

beforeCreate (创建实例) created (创建完成) 、beforeMount (开始创建模板) mounted (创建完成) 、beforeUpdate (开始更新) updated (更新完成) 、beforeDestroy (开始销毁) destroyed (销毁完成)

![图示

描述已自动生成]()

![图示

描述已自动生成]()

第一次页面加载会触发哪几个钩子

beforeCreatecreatedbeforeMountmounted

 

自定义事件

通过ref属性拿到TestA组件组件的实例对象(vc),在组件挂载完成之后(mounted)使用this.refs.组件名.refs.组件名.on('自定义事件名', 回调函数)完成对子组件自定义事件的绑定父组件中需要改变的:

 

![图形用户界面, 文本

描述已自动生成]()

segmentfault.com/a/119000004…

vue 在 created 和 mounted 这两个生命周期中请求数据有(什么区别呢?

看实际情况, 一般在created (或beforeRouter)  里面就可以, 如果涉及到需要页面加载完成之后的话就用 mounted。

在 created 的时候, 视图中的 html 并没有渲染出来, 所以此时如果直接去操作 html 的 dom 节点, 一定找不到相关的元素

而在mounted 中, 由于此时 html 已经渲染出来了, 所以可以直接操作 dom 节点, (此时 document.getelementById 即可生效了)

DOM渲染在哪个生命周期中完成


DOM 渲染在 mounted 周期中就已经完成

SPA与前端路由

  • SPA(单页面应用,全程为:Single-page Web applications)指的是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序,简单通俗点就是在一个项目中只有一个html页面,它在第一次加载页面时,将唯一完成的html页面和所有其余页面组件一起下载下来,所有的组件的展示与切换都在这唯一的页面中完成,这样切换页面时,不会重新加载整个页面,而是通过路由来实现不同组件之间的切换。
  • 单页面应用(SPA)的核心之一是:更新视图而不重新请求页面。 优点:
  • 具有桌面应用的即时性、网站的可移植性和可访问性
  • 用户体验好、快,内容的改变不需要重新加载整个页面
  • 良好的前后端分离,分工更明确

缺点:

  • 不利于搜索引擎的抓取
  • 首次渲染速度相对较慢

 

Vue路由模式hash、history简单讲一下。

hash的特点

·        hash变化会触发网页跳转,即浏览器的前进和后退。

·        hash 可以改变 url ,但是不会触发页面重新加载(hash的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url

·        hash 通过 window.onhashchange 的方式,来监听 hash 的改变,借此实现无刷新跳转的功能。

·        hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)。

对于 history 来说,主要有以下特点:

  • 新的 url 可以是与当前 url 同源的任意 url ,也可以是与当前 url 一样的地址,但是这样会导致的一个问题是,会把重复的这一次操作记录到栈当中。
  • 通过 history.state ,添加任意类型的数据记录中。
  • 可以额外设置 title 属性,以便后续使用。到
  • 通过 pushState 、 replaceState 来实现无刷新跳转的功能。

与hash的区别

![图形用户界面, 文本, 应用程序, 电子邮件

描述已自动生成]()

在使用 history 模式时,需要通过服务端来允许地址可访问,如果没有设置,就很容易导致出现 404 的局面。

1、 history和hash都是利用浏览器的两种特性实现前端路由,history是利用浏览历史记录栈的API实现,hash是监听location对象hash值变化事件来实现

 

2、 history的url没有’#'号,hash反之

 

3、 相同的url,history会触发添加到浏览器历史记录栈中,hash不会触发,history需要后端配合,如果后端不配合刷新新页面会出现404,hash不需要

 

4、

HashRouter的原理:通过window.onhashchange方法获取新URL中hash值,再做进一步处理 HistoryRouter的原理:通过history.pushState 使用它做页面跳转不会触发页面刷新,使用window.onpopstate 监听浏览器的前进和后退,再做其他处理

原文链接:blog.csdn.net/weixin_4658…

hash模式  hash是指url尾巴后的#号及后面的字符。  这里的#和css里的#是一个意思。hash也称作锚点  hash值变化不会导致浏览器向服务器发出请求  hash改变会触发hashchange事件 

 history模式  HTML5规范提供了history.pushState和history.replaceState来进行路由控制。  通过这两个方法可以改变url且不向服务器发送请求。  同时不会像hash有一个#,更加的美观。  但是history路由需要服务器的支持,并且需将所有的路由重定向到根页面。   区别:  hash:监听 url 中 hash 的变化,然后渲染不同的内容,这种路由不向服务器发送请求,不需要服务端的支持;  history:监听 url 中的路径变化,需要客户端和服务端共同的支持;

 

Vue传参的两种方式,params和query方式与区别

动态路由也可以叫路由传参, 就是根据不同的选择在同一个组件渲染不同的内容

 (3) 动态路由传参 地址栏显示 刷新不丢失

        /user/1234

        { path: '/user/:userid', component: User }  必须配合动态路由规则使用

 

        this.$router.push('/user/1234')

        this.$router.push({

            path: '/user/123124'

        })

 

 

        获取: this.$route.params.userid

用法上: query 用path 引入, params 用name 引入, 接收参数都是类似的, 分别是 this.route.query.namethis.route.query.name 和 this.route.params.name

![文本

描述已自动生成]()

![文本

描述已自动生成]()

query 传过来的参数会显示到地址栏中 **** params 传过来的参数不会显示到地址栏中 ****直白的来说 query 相当于 get 请求,而 params 相当于 post 请求两者中 query 在刷新页面的时候参数不会消失 **** params 在刷新页面的时候参数会消失 ****可以考虑本地存储解决此问题![文本, 信件

描述已自动生成]()

Vue路由跳转传参?

    3种

    (1) query传参  地址栏显示 刷新不丢失

         this.$router.push('/login?username=zs&age=18')

         this.$router.push({

            path: '/login',

            query: {

               username: 'zs',

               age: 19

            }

         })

 

         获取: this.$route.query.xxxx

 

    (2) params传参  不会在地址栏显示 内存中传递 刷新数据会丢失(配合localStorage)

        必须配合name 命名路由使用

 

        import Login from '....'

        { path: '/login', component: Login, name: 'login' }

 

        this.$router.push({

            name: 'login',

            params: {

               car: '老四莱斯'

            }

        })

 

        获取: this.$route.params.xxx

 

    (3) 动态路由传参 地址栏显示 刷新不丢失

        /user/1234

        { path: '/user/:userid', component: User }  必须配合动态路由规则使用

 

        this.$router.push('/user/1234')

        this.$router.push({

            path: '/user/123124'

        })

 

 

        获取: this.$route.params.userid

 

Vue 路由声明方式****

Vue 中路由跳转有两种, 分别是声明式和编程式

Replace

该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)

 

它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。

Get post 不同****

Get 是从服务器上获取数据, post 是向服务器传送数据

在客户端, get 通过url 提交数据, 数据在url 中可以看到, post 方式, 数据放在 html header 中提交

安全性问题

Get 提交数据最多只能有 1024 字节, post 没有限制

补充get和post请求缓存方面的区别

post/get 的请求区别,具体不再赘述。补充补充一个 get 和 post 在缓存方面的区别: get 请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。

post 不同,post 做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此 get 请求适合于请求缓存。

Vue 路由钩子函数 / 路由守卫有哪些?****

全局守卫: beforeEach (to, from, next) 和afterEach (to, from)

路由独享守卫: beforeEnter

组 件 内 的 守 卫 :  路 由 进 入 / 更 新 / 离 开 之 前beforeRouterEnter/update/leave

Route 与 router区别

router 是 VueRouter 的一个对象, 通过 Vue.use(VueRouter)和VueRouter 构造函数得到一个 router 的实例对象,这个对象中是一个全局的对象, 他包含了所有的路由包含了许多关键的对象和属性。

route 是一个跳转的路由对象, 每一个路由都会有一个route 对象, 是一个局部的对象, 可以获取对应的 name,path,params,query 等

 

Vue数据绑定的几种方式

单向绑定 双大括号 {{}} html 内字符串绑定

v-bind 绑定 html 属性绑定

双向绑定 v-model

一次性绑定 v-once 依赖于 v-model

Vue中有两种数据绑定方式:

1.单向数据绑定(v-bind):数据只能从data流回页面(单向传递)

2.双向数据绑定(v-model):数据不仅可以从data流向页面,还可以从页面流向data

(1)双向数据绑定一般都应用在表单类元素上(如:input select checkbox等)

(2)v-model:value 可以简写为 v-model 因为v-model默认收集的就是value值

Vue 双向绑定的原理

Vue 双向绑定就是: 数据变化更新视图, 视图变化更新数据。Vue 数据双向绑定是通过数据劫持和观察者模式来实现的,

数据劫持, object.defineproperty 它的目的是: 当给属性赋值的时候, 程序可以感知到, 就可以控制改变属性值

观察者模式 当属性发生改变的时候, 使用该数据的地方也发生改变

Vue 双数据绑定过程中,这边儿数据改变了怎么通知另一边改变

数据劫持和观察者模式

Vue 数据双向绑定是通过数据劫持和-

者模式来实现的,

数据劫持, object.defineproperty 它的目的是: 当给属性赋值的时候,

程序可以感知到, 就可以控制属性值的有效范围, 可以改变其他属性的值

观察者模式它的目的是当属性发生改变的时候, 使用该数据的地方也发

生改变

vue的双向数据绑定原理是什么?

vue数据双向绑定是通过数据劫持结合“发布者-订阅者模式”的方式来实现的。 vue是通过Object.defineProperty()来实现数据劫持,其中会有getter()和setter方法;当读取属性值时,就会触发getter()方法,在view中如果数据发生了变化,就会通过Object.defineProperty()对属性设置一个setter函数,当数据改变了就会来触发这个函数;

vue 的数据劫持有两个缺点:

1、无法监听通过索引修改数组的值的变化

2、无法监听 object 也就是对象的值的变化所以 vue2.x 中才会有$set 属性的存在

proxy 是es6 中推出的新 api,可以弥补以上两个缺点,所以 vue3.x 版本用 proxy 替换 object.defineproperty。

 

Vue注册一个全局组件

Elementui中的常用组件有哪些?请简述你经常使用的 并且他们的属性有哪些?

Vue 中指令有哪些

v-for、v-on、v-bind、v-model、v-if v-else v-else-if、v-show、v-html、v-text、{{}}、v-once、v-clock、v-pre、

v-for: 循环数组, 对象, 字符串, 数字

v-on: 绑定事件监听

 v-on 可以绑定多个方法吗

可以 如果绑定多个事件,可以用键值对的形式事件类型:事件名

如果绑定是多个相同事件, 直接用逗号分隔就行。

v-on

为元素绑定事件可以直接在元素上 v-on:click="``方法名称``()" ,或者简写成 @click="``方法名称``()"

对应的方法要写在Vue对象中的 methods 中,在指令中想要访问data属性中的数据,可以通过this加上自己定义的属性名即可,this.``自定义属性名称

 

v-bind: 动态绑定一个或者多个属性

v-model: 表单控件或者组件上创建双向绑定

v-if v-else v-else-if 条件渲染

v-show 根据表达式真假, 切换元素的 display

v-show、v-if

v-if 根据条件渲染或者销毁元素,而v-show只会控制元素的显示和隐藏,相当于改变display值

![屏幕上有字

描述已自动生成]()

v-if更多的用于条件判断

 

v-html 更新元素的 innerhtml

v-text(#v-html(类似于原生js中的innerhtml、innertext)

图标

描述已自动生成{{}} 图标

描述已自动生成   v-html 图标

描述已自动生成

v-html不仅可以渲染数据,而且可以解析标签

v-text和{{}}表达式渲染数据,不解析标签。(胡子语法和{{}}是一个东西)

与花括号的区别是在页面加载时不显示双花号

v-text 指令:

作用: 操作网页元素中的纯文本内容。{{}}是他的另外一种写法v-text 与{{}}区别:

v-text 与{{}}等价, {{}}叫模板插值, v-text 叫指令。

有一点区别就是, 在渲染的数据比较多的时候, {{}}可能会把大括号显示出来, 俗称屏幕闪动。

 

v-text 更新元素的 textcontent

v-pre 跳过这个元素和子元素的编译过程

跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

v-clock 这个指令保持在元素上知道关联实例结束编译

#v-cloak

cloak:斗篷,遮挡物;浏览器可能会直接显示未编译的Mustache标签,所以v-cloak可以避免这个问题

![文本

描述已自动生成]()

v-once 只渲染一次

对 yue 中keep-alive 的理解

概念: keep-alive 是vue 的内置组件, 当它动态包裹组件时, 会缓存不活动的组件实例, 它自身不会渲染成一个 DOM 元素也不会出现在父组件链中

作用: 在组件切换过程中将状态保留在内存中, 防止重复渲染DOM, 减

少加载时间以及性能消耗, 提高用户体验。

生命周期函数: Activated 在keep-alive 组件激活时调用, deactivated 在 keep-alive 组件停用时调用

KeepAlive

KeepAlive用于处理组件缓存。有什么用呢?想象一个业务场景:

在Login页面填写完手机号,发现未注册,需要跳去Register页面完成注册,再返回Login页面填写密码,进行登录,此时如果在Login页面没有保存好手机号,那么跳回来时,用户又得重新输入手机号。为了解决这样的需求,我们需要借助keep-alive。

动态组件

有些场景会需要在两个组件间来回切换,比如 Tab 界面:

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过  组件强制被切换掉的组件仍然保持“存活”的状态。

如何让组件中的css在当前组件生效

在 styled 中加上 scoped

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

Data 是一个函数时, 每个组件实例都有自己的作用域, 每个实例相互独立, 不会相互影响

如果是引用类型 (对象), 当多个组件共用一个数据源时,一处数据改变, 所有的组件数据都会改变,所以要利用函数通过return 返回对象的拷贝, (返回一个新数据), 让每个实例都有自己的作用域, 相互不影响。

Vue 中组件怎么传值

正向: 父传子 父组件把要传递的数据绑定在属性上, 发送, 子组件通过props 接收

 

逆向: 子传父 子组件通过 this.$emit (自定义事件名, 要发送的数据), 父组件设置一个监听事件来接收, 然后拿到数据

![图形用户界面, 文本

描述已自动生成]()

![文本

描述已自动生成]()

兄弟: eventbus 中央事件总线通过 Vuex

![文本

描述已自动生成]()

![图形用户界面, 应用程序

描述已自动生成]()

Bootstrap应用场景

网格系统的实现原理, 通过定义容器大小, 平分 12 份, ( 24 份或者 32 份), 再调整内外边距, 结合媒体查询, 就成了强大的响应式网格系统。

插槽请简述

大概分这几点,首先槽口(插槽) 可以放什么内容? 放在哪? 什么作用? 可以放任意内容, 在子组件中使用, 是为了将父组件中的子组件模板数据正常显示。

 

具名插槽和匿名插槽, 作用域插槽, 说白了就是在组件上的属性, 可以在组件元素内使用,

 

可以在父组件中使用 slot-scope 从子组件获取数据

插槽的作用?

  1. 组件通过插槽传入自定义结构
  2. 用于实现组件的内容分发, 通过 slot 标签, 可以接收到写在组件标签内的内容
  3. vue提供组件插槽能力, 允许开发者在封装组件时,把不确定的部分定义为插槽

插槽的种类及作用

默认插槽

![图示

描述已自动生成]()

具名插槽

使用背景:

当一个组件内有2处以上需要外部传入标签的地方

![图示, 日程表

描述已自动生成]() 

特性:

  1. slot有可以设置多个
  2. 定义组件时:slot的name属性起插槽名
  3. 使用组件时, template配合#插槽名传入具体html标签或组件

v-slot一般跟template标签使用 (template是html5新出标签内容模板元素, 不会渲染到页面上, 一般被vue解析为内部标签)

作用域插槽:

步骤:

  • 创建子组件, 准备slot, 在slot上绑定属性和子组件值
  • 使用子组件, 传入自定义标签, 用template和v-slot="自定义变量名"
  • 自定义变量名会自动绑定slot上所有属性, 就可以使用子组件内值, 并替换slot位置

小结:

组件内变量绑定在slot上, 然后使用组件v-slot:插槽名字="变量" ,变量上就会绑定slot传递的属性和值

![电脑萤幕画面

描述已自动生成]()

插槽****

为子组件传递 一些模板片段,让子组件在它们的组件中渲染这些片段。

插槽内容可以是任意合法的模板内容,不局限于文本。例如我们可以传入多个元素,甚至是组件

通过使用插槽,<FancyButton> 组件更加灵活和具有可复用性。现在组件可以用在不同的地方渲染各异的内容,但同时还保证都具有相同的样式。

渲染作用域

插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。         

插槽内容无法访问子组件的数据。

具名插槽、作用域插槽

Vue 首屏加载慢的原因,怎么解决的,白屏时间怎么检测,怎么解决白屏问题?

首屏加载慢的原因:

第一次加载页面有很多组件数据需要渲染

解决方法:

1.路由懒加载 component: () = >import(“路由地址”)

2.ui 框架按需加载

3.gzip 压缩

白屏时间检测:

????

解决白屏问题:

②  使用 v-text 渲染数据

②使用{{}}语法渲染数据, 但是同时使用 v-cloak 指令 (用来保持在元素上直到关联实例结束时候进行编译), v-cloak 要放在什么位置呢 , v-cloak 并不需要添加到每个标签, 只要在 el 挂载的标签上添加就可以

Vuex流程

在vue 组件里面, 通过dispatch 来触发actions 提交修改数据的操作, 然后通过actions 的 commit 触发 mutations 来修改数据, mutations 接收到commit 的请求, 就会自动通过 mutate 来修改 state, 最后由store 触发每一个调用它的组件的更新

//Vuex 怎么请求异步数据

首先在 state 中创建变量

然后在action 中调用封装好的 axios 请求, 异步接收数据, commit 提交给 mutations

Mutations 中改变 state 中的状态, 将从 action 中获取到的值赋值state

Vuex中action 如何提交给 mutation 的

Action 函数接收一个与store 实例具有相同方法和属性的 context 对象,可以调用context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 获取 state 和 getters

vuex的State特性是?

State 就是数据源的存放地

State 里面的数据是响应式的, state 中的数据改变, 对应这个数据的组

件也会发生改变

State 通过 mapstate 把全局的 state 和 getters 映射到当前组件的计算属性中

vuex的 Getter 特性是?

Getter 可以对 state 进行计算操作, 它就是 store 的计算属性

Getter 可以在多组件之间复用

如果一个状态只在一个组件内使用, 可以不用getters

//yuex的 Mutation 特性是?

更改vuex store 中修改状态的唯一办法就是提交 mutation,可以在回调函数中修改 store 中的状态

//vuex的actions 特性是?

Action 类似于 mutation, 不同的是action 提交的是 mutation, 不是直接变更状态, 可以包含任意异步操作

Pinia优点

完整的 ts 的支持;

足够轻量,压缩后的体积只有1kb左右;

去除 mutations,只有 state,getters,actions;

actions 支持同步和异步;

代码扁平化没有模块嵌套,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的

无需手动添加 store,store 一旦创建便会自动添加;

支持Vue3 和 Vue2

 

vuex的优势和劣势

优点: 解决了非父子组件的通信, 减少了ajax 请求次数, 有些可以直接从 state 中获取

缺点: 刷新浏览器, vuex 中的state 会重新变为初始状态, 解决办法是vuex-along, 得配合计算属性和 sessionstorage 来实现

V-for与 v-if 优先级

首先不要把v-if 与v-for 用在同一个元素上,原因: v-for 比v-if 优先

如果每一次都需要遍历整个数组, 将会影响速度,尤其是当只需要渲染很小一部分的时候。

什么是虚拟 dom

Virtual DOM 是 DOM 节点在 JavaScript 中的一种抽象数据结构,之所以需要虚拟 DOM,是因为浏览器中操作 DOM 的代价比较昂贵,频繁操作 DOM 会产生性能问题。

虚拟 DOM 的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue 对比更新前后的虚拟 DOM,匹配找出尽可能少的需要更新的真实 DOM,从而达到提升性能的目的。

虚拟 DOM 的实现原理主要包括以下 3 部分:

  • 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
  • diff 算法 — 比较两棵虚拟 DOM 树的差异;
  • pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

vue-router和location.href的用法区别

 · vue-router使用pushState进行路由更新,静态跳转,页面不会重新加载;

 · location.href会触发浏览器,页面重新加载一次

 · vue-router使用diff算法,实现按需加载,减少dom操作

 · vue-router是路由跳转或同一个页面跳转;location.href是不同页面间跳转;

 · vue-router是异步加载this.$nextTick(()=>{获取url});location.href是同步加载

如何解决 vue 初始化页面闪动问题

使用 vue 开发时,在 vue 初始化之前,由于 div 是不归 vue 管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于 {{message}} 的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。

首先:在 css 里加上 [v-cloak] { display: none; } 。如果没有彻底解决问题,则在根元素加上 style="display: none;" :style="{display:  block }"

 

说说你对 proxy 的理解

Vue3.0是如何变得更快的?(底层,源码)

a.  diff 方法优化

Vue2 . x 中 的 虚 拟 dom   是 进 行 全 量 的 对 比 。

b.  Vue3 . 0   中 新 增 了 静 态 标 记    ( PatchFlag) :    在 与 上 次 虚 拟 结 点 进 行 对比的 时候,   值对 比带有 patch flag   的节 点,   并且 可以通 过    flag   的信息得 知 当 前 节 点 要 对 比 的 具 体 内 容 化 。 hoistStatic 静 态 提 升

Vue2 . x :  无论元素是否参与更新,   每次都会重新创建。

Vue3 . 0 : 对不参与更新的元素, 只会被创建一次, 之后会在每次渲染时候被不停的复用。

c.  cacheHandlers 事件侦听器缓存

默认情况下 onClick 会被视为动态绑定, 所以每次都会去追踪它的

变化但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可。

React

 

1.                                                                           图片包含 游戏机, 画

描述已自动生成图片包含 图标

描述已自动生成react





React 起源于facebook, react 是一个用于构建用户界面的js 库

声明式设计: react 采用范式声明, 开发者只需要声明显示内容, react

就会自动完成

:   react 通过对 dom 的模拟 (也就是虚拟dom), 最大限度的减少与 dom 的交互

 

![图标

描述已自动生成]():    react 可以和已知的库或者框架很好配合

 

:   通过react 构建组件, 让代码更容易复用, 能够很好应用在大型项目开发中, 把页面功能拆分成小模块 每个小模块就是组件

 

:   react 是单向数据流, 数据通过props 从父节点传递到子节点, 如果父级的某个props 改变了, react 会重新渲染所有的子节点

2.     react





正向传值用 props

逆向传值用函数传值 通过事件调用函数传递同级传值用 pubsub-js

用pubsub.publish (事件名, 数据) 抛出数据

用 pubsub.subscribe (监听的事件, () =) {}) 接收数据

跨组件传递    用 context 要使用 context 进行跨组件传值就需要使用createContext() 方法,                    这 个 方 法 有 两 个 对 象 provider                             生 产

者    Consumer 消费者

![卡通画

中度可信度描述已自动生成]():

都支持服务器渲染

都有虚拟dom,组件化开发,通过props 参数进行父子组件数据的传递, 都实现 webcomponent 规范

都是数据驱动视图

都有状态管理, react 有redux, vue 有vuex

都有支持 native’的方案 react 有 react native vue 有 weex

 

react 严格上只针对mvc 的view 层, vue 是mvvm 模式

虚拟dom 不一样, vue 会跟踪每一个组件的依赖关系, 不需要重新渲染整个dom 组件树, 而react 不同, 当应用的状态被改变时, 全部组件都会重新渲染, 所以 react 中用 shouldcomponentupdate 这个生命周期的钩子函数来控制

组件写法不一样 , react 是jsx 和inline style , 就是把html 和css 全写进js 中, vue 则是html, css , js 在同一个文件

数据绑定不一样, vue 实现了数据双向绑定, react 数据流动是单向的

在react 中,state 对象需要用 setstate 方法更新状态,在 vue 中,state 对象不是必须的, 数据由data 属性在 vue 对象中管理

react 文本

描述已自动生成



componentWillMount 组件渲染之前调用componentDidMount 在第一次渲染之后调用

componentWillReceiveProps 在组件接收到一个新的 props 时调用shouldComponentUpdate 判断组件是否更新 html componentWillupdate 组件即将更新 html 时调用componentDidupdate 在组件完成更新后立即调用componentWillUnmount 在组件移除之前调用

14.


React 负责渲染表单的组件, 值是来自于state 控制的, 输入表单元素称为受控组件

 

数据更新延迟的问题

当侦听到你的数据发生变化时, Vue将开启一个队列(该队列被Vue官方称为异步更新队列)。视图需要等队列中所有数据变化完成之后,再统一进行更新

 

$nextTick

nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。

应用场景

1、          如果要在created()钩子函数中进行的DOM操作,由于created()钩子函数中还未对DOM进行任何渲染,所以无法直接操作dom,需要通过$nextTick()来完成。

Vue怎么操作dom

过 ref 来获取dom元素

通过ID 获取DOM对象

不过这种方法对于被重用的组件来说是有问题的,因为这个预置防抖的函数是 有状态的:它在运行时维护着一个内部状态。如果多个组件实例都共享这同一个预置防抖的函数,那么它们之间将会互相影响。

要保持每个组件实例的防抖函数都彼此独立,我们可以改为在 created 生命周期钩子中创建这个预置防抖的函数:

![文本

描述已自动生成]()

![图形用户界面

描述已自动生成]()

Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

替换一个数组#

变更方法,顾名思义,就是会对调用它们的原数组进行变更。相对地,也有一些不可变 (immutable) 方法,例如 filter()concat() 和 slice(),这些都不会更改原数组,而总是返回一个新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的

 

![文本

描述已自动生成]()

项目打包上线

Npm run build

购买云服务器

设置安全组放开端口

应用xshell工具登陆服务器

xftp本地文件上传至云服务器

配置nginx反向代理

Vue动态绑定class类。

最简单的绑定

:class="{ 'active': isActive }"

绑定并判断多个****

第一种(用逗号隔开)

:class="{ 'active': isActive, 'sort': isSort }"

单纯数组****

:class="[isActive,isSolrt]"

Vue想在父组件中执行子组件中的方法

1、在父组件中,通过ref直接调用子组件的方法;

2、在父组件中,通过组件的“emit”、“emit”、“on”方法来调用。

Vue自定义指令

自定义指令一般分为组件私有自定义指令和项目全局自定义指令。它们的定义方式类似于filters过滤器的的定义。

一:私有自定义指令:( 只能在定义的组件内使用

在组件中的directives中定义一个指令,通过bing和update函数实现该指令需要表达的逻辑。

  //初次加载组件时调bind函数处理绑定v-color的DOm节点

//当data中color数据发生改变时,update函数实现更新Dom节点

二: 全局自定义指令

在全局入口文件main.js中定义全局自定义指令,一次定义,可以在项目任何组件中使用。

9个常用的Vue自定义指令

文字左右横线指令 v-striping

复制粘贴指令 v-copy

长按指令 v-longpress

输入框防抖指令 v-debounce

禁止表情及特殊字符 v-emoji

图片懒加载 v-LazyLoad

权限校验指令 v-premission

实现页面水印 v-waterMarker

拖拽指令 v-draggable

业务组件

底边栏

头部栏

三级联动

面包屑

Vite/Webpack

vite 对比 webpack ,优缺点在哪

 

优点:

  1. 更快的冷启动:Vite 借助了浏览器对 ESM 规范的支持,采取了与 Webpack 完全不同的 unbundle 机制
  2. 更快的热更新:Vite 采用 unbundle 机制,所以 dev server 在监听到文件发生变化以后,只需要通过 ws 连接通知浏览器去重新加载变化的文件,剩下的工作就交给浏览器去做了。

缺点:

  1. 开发环境下首屏加载变慢:由于 unbundle 机制,Vite 首屏期间需要额外做其它工作。不过首屏性能差只发生在 dev server 启动以后第一次加载页面时发生。之后再 reload 页面时,首屏性能会好很多。原因是 dev server 会将之前已经完成转换的内容缓存起来
  2. 开发环境下懒加载变慢:跟首屏加载变慢的原因一样。Vite 在懒加载方面的性能也比 Webpack 差。由于 unbundle 机制,动态加载的文件,需要做 resolve、load、transform、parse 操作,并且还有大量的 http 请求,导致懒加载性能也受到影响。
  3. webpack 支持的更广。由于 Vite 基于ES Module,所以代码中不可以使用CommonJs;webpack更多的关注兼容性, 而Vite 关注浏览器端的开发体验。Vite目前生态还不如 Webpack。

当需要打包到生产环境时,Vite使用传统的rollup进行打包,所以,vite的优势是体现在开发阶段,缺点也只是在开发阶段存在。

通信

请求参数格式

segmentfault.com/a/119000002…

*1. Query String Parameters 格式: `?key=value&key=value```

参数会以 url string 的形式进行传递,即?后的字符串则为其请求参数,并以&作为分隔符。常用在 GET 请求方式时使用。 其他请求方式也可以使用,拼接在接口地址 url? 后面。

*2. Form Data 格式:key=value&key=value 键值对形式

Form Data 格式:key=value&key=value 键值对形式

参数会以 Form Data 的形式(数据为 String 键值对格式)传递给接口,并且不会显示在接口 url 上。

对表单提交和文件上传时做特殊处理,需要使用 new FormData() 方法处理后传递给接口服务器为什么会对表单提交和文件上传做特殊处理,因为表单提交数据是名值对的方式,且Content-Type为application/x-www-form-urlencoded,而文件上传服务器需要特殊处理,普通的post请求(Content-Type不是application/x-www-form-urlencoded)数据格式不固定,不一定是名值对的方式,所以服务器无法知道具体的处理方式,所以只能通过获取原始数据流的方式来进行解析。

*3. Request Payload 格式:{key: value, key: value} (后端经过反序列化得到对象)

参数会以 Request Payload 的形式(数据为 json 格式)传递给接口,并且不会显示在接口 url 上。

 

http有哪些方法

   get获取  post新增  put重置修改  patch部分修改   delete删除

请求报文 响应报文

  请求报文: 请求行 请求头 请求体

  响应报文: 响应行 响应头 响应体

http状态码

  200 成功    201 新建

  301/302  重定向    304 协商缓存  ??

  400 接口传参错误   401 权限认证失败

  403 请求资源拒绝   404 找不到资源

  5xx 服务器错误

http 状态码都有哪些

状态码第一位数字决定了不同的响应状态,如下:

·        1 表示消息

·        2 表示成功

·        3 表示重定向

·        4 表示请求错误

·        5 表示服务器错误

 

100:这个状态码是告诉客户端应该继续发送请求,这个临时响应是用来通知客户端的, 部分的请求服务器已经接受, 但是客户端应继续发送求请求的剩余部分, 如果请求已经完成, 就忽略这个响应, 而且服务器会在请求完成后向客户发送一个最终的结果

200: 这个是最常见的 http 状态码, 表示服务器已经成功接受请求, 并 将返回客户端所请求的最终结果

202: 表示服务器已经接受了请求, 但是还没有处理, 而且这个请求最终会不会处理还不确定

204: 服务器成功处理了请求, 但没有返回任何实体内容 ,可能会返回 新的头部元信息

301: 客户端请求的网页已经永久移动到新的位置, 当链接发生变化时, 返回 301 代码告诉客户端链接的变化, 客户端保存新的链接, 并向新的 链接发出请求, 已返回请求结果

404: 请求失败, 客户端请求的资源没有找到或者是不存在

500: 服务器遇到未知的错误, 导致无法完成客户端当前的请求。

503: 服务器由于临时的服务器过载或者是维护, 无法解决当前的请求

http 与 https的区别

  https 相比于 http  更安全

  https 在数据传输时 进行数据的加密处理 更安全

WebSoket

WebSocket 是一种在单个 TCP 连接上进行全双工通信(通信的双方可以同时发送和接收信息的信息交互方式)的网络协议。它是 HTML5 中的一种新特性,能够实现 Web 应用程序和服务器之间的实时通信,比如在线聊天、游戏、数据可视化等。

相较于 HTTP 协议的请求-响应模式,使用 WebSocket 可以建立持久连接,允许服务器主动向客户端推送数据,避免了不必要的轮询(由CPU定时发出询问,依序询问每一个周边设备是否需要其服务,有即给予服务,服务结束后再问下一个周边,接着不断周而复始)请求,提高了实时性和效率。

WebSocket 协议是基于握手协议(Handshake Protocol)的,它在建立连接时使用 HTTP/HTTPS 发送一个初始握手请求,然后服务器响应该请求,建立连接后就可以在连接上进行数据传输了。

总之,WebSocket 提供了一种快速、可靠且灵活的方式,使 Web 应用程序能够实现实时通信,同时也提高了网络性能和用户体验。

使用场景****

1.     实时性要求较高的应用,比如在线聊天、游戏、数据可视化等;

2.     需要频繁交换数据的应用,比如在线编辑器、文件管理器等;

3.     需要推送服务的应用,比如实时数据监控、通知系统等;

4.     跨平台的应用,比如桌面应用程序、移动应用程序等。

 

js函数中的参数是以什么方式进行传递的??

   值类型  引用类型

   (1) 简单数据类型(string number boolean null undefined symbol)

       传递的就是值本身, 不会互相影响

 

   (2) 复杂数据类型

       传递的是复杂类型数据的地址, 会互相影响!!!

 

js中的继承

   3种  原型继承  组合式继承  寄生组合式继承

   (1) 原型继承: 原型替换

   Student 的实例 继承  Person 的属性方法

   Student.prototype = new Person()

   (2) 组合式继承: 原型替换 + 构造函数借调

      2.1 原型替换  => 继承方法

        子构造函数.prototype = new 父构造函数()

      2.2 构造函数 借调 =>  继承实例属性

        父构造函数.call(this, xxxx, xxx)

   (3) 寄生组合式继承: 原型替换 + 构造函数借调 + Object.create()优化

      3.1 原型替换  => 继承方法

        子构造函数.prototype = new 父构造函数()

 

      3.2 构造函数 借调 =>  继承实例属性

        父构造函数.call(this, xxxx, xxx)

 

      3.3 Object.create基于传入的一个对象, 创建一个新对象, 新对象的__proto__直接指向传入的对象

          Student.prototype = Object.create(Person.prototype)

 

 

      相比于组合继承  将替换的原型 由原来的 new  ===>>>>  Object.create创建 省了一个new的过程,

      直接形成原型关系

 

es6提出了   extends      class Student extends Person {....}

如何保证安全?

  (1) https加密方案: 非对称加密 + 对称加密

      非对称加密 加密传输 对称加密的密钥!!!!  => 保证密钥安全

      对称加密是用于加密数据的, 但是对称加密的密钥容易泄露  => 保证数据安全且加密效率高

  (2) 数字证书: 加密签发公钥

      访问一个网站时, 你要和网站请求数据, 数据是加密过的, 数据需要解密, 需要拿到对称加密的密钥!!

      对称加密的密钥 是 非对称加密来的!   得需要拿到非对称加密的公钥/私钥

 

      客户端和服务器 初步通信 客户端发送请求 可以拿到数字证书, 也就是拿到了所谓的公钥!!!

 

      数字证书 一般是由专业的机构签发, 包含网站基本信息 到期时间 公钥...

 

 

  (3) 数字签名: 防篡改证书

      数字证书

       网站: xxx.xxx.xxx

       公钥: xxcdasdfafsafd

       到期时间: 2029年10月1日

       签发机构: CA机构

       签名: 上面所有信息的hash加密结果  dsfahjkksdhfkjashl

 

 


 

有哪些加密方案?

  1. 对称加密: 同一个密钥 既能加密 也能解密,  可逆

   优点: 计算量小 加密速度快 加密效率高

   缺点: 如果一开始密钥泄露了, 没有任何安全性

 

  1. 非对称加密: 两把密钥(公钥 私钥)  可逆

   优点: 更安全

   缺点: 麻烦 加密和解密花费的时间会更长 速度慢 效率低  只适合处理少量的加密

 

   ssh免密登录   需要本地生成两把钥匙公钥 私钥     公钥给到了gitee

   本地电脑(私钥)        =>         gitee(公钥)

   本地电脑(私钥)        <=         gitee(公钥)

  

  1. hash算法加密   不可逆的(无法回退到明文) 根据加密算法 生成一段唯一标识

   179823qwer   =>   fsadjkldfhjsaklhdf

 

   后台数据库一般存储密码 都需要进行hash算法加密!!

   md5 比较老的加密算法 容易因为撞库操作 导致密码不安全

   sha256

 

   1 => sds

   17 => sadfsda

   179823 => asdfsad

   .....

   179823qwer => fsadjkldfhjsaklhdf

 

  

17.http2与http1的区别?

   1.http2 二进制传输数据  http1 文本传输  二进制解析更高效

   2.http2 采用头部压缩 减少请求头中重复携带的数据, 减小服务器压力

   3.http2 服务器推送方式, 可以向客户端主动推送数据(websocket)

   4.http2 多路复用机制, 少创建一些连接  单个连接可以承载任意数量的双向数据流

 

 

一次完整的http服务的过程?  => 地址栏输入www.baidu.com 发生了什么??

   1. 对www.baidu.com 做DNS解析, 将域名解析成ip的过程(DNS解析优先找本机的hosts文件, 如果本机没有配置相关域名的ip, 会去公网找dns服务器, 解析得到ip)

www.baidu.com => 112.80.248.76

   2. 根据ip找到对应的服务器  建立tcp连接(三次握手)

   -------------------------------------------------------------

   3. 建立连接成功后, 进行http请求(拿百度首页index.html)

   4. 服务器响应http请求, 返回index.html, 浏览器拿到了html文件

   5. 浏览器解析html文件时, 遇到link script img去请求其他的资源(css js 图片)

   6. 浏览器将完整的页面渲染好 呈现给用户

   --------------------------------------------------------------

   7. 服务完成,关闭tcp连接(四次挥手)

一个页面从输入URL到页面加载显示完成,经历了什么?

  1. 当发送一个 URL 请求时,不管这个 URL 是 Web 页面的 URL 还 是 Web 页面上每个资源的 URL,浏览器都会开启一个线程来处理这个请求,同时在远程 DNS 服务器上启动一个 DNS 查询。这能使浏览器获得请求对应的 IP 地址。

  2. 浏览器与远程 Web 服务器通过 TCP 三次握手协商来建立一个 TCP/IP 连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,然后服务器响应并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。

  3. 一旦 TCP/IP 连接建立,浏览器会通过该连接向远程服务器发送 HTTP 的 GET 请求。远程服务器找到资源并使用 HTTP 响应返回该资源

  4. 此时,Web 服务器提供资源服务,客户端开始下载资源

 

三次握手?  双方确认

    三次握手是必须的!  确认双方的收发信息的能力

 

    第一次握手: 客户端往服务端发消息  喂?能听到么?

      本质上是服务端确定了: 服务端能收消息  客户端能发消息

 

    第二次握手: 服务端给客户端回消息  能听到 你能听到我说话么?

      本质上是客户端确定了:  服务端发消息的能力 客户端收消息的能力  客户端发消息的能力 服务端收消息的能力

 

    第三次握手: 客户端要给服务端回消息  我也能听到!

      本质上是服务端确认了: 客户端收消息的能力 服务端发消息的能力 客户端发消息的能力 服务端收消息的能力

 

 

四次挥手? 严谨(确认彼此的话说完了)

   服务已经完成 想要断开连接

 

   第一次挥手: 客户端主动发起 想要断开连接         哥们,我已经说完了 你还有想说的么?

 

   第二次挥手: 服务端回应                       我知道了, 你等会, 我确认一下 还有没有什么没有传输完?

 

   .......

 

   第三次挥手: 服务器回应                        哥们,我确认了一下, 我传输(说)完了,没有要补充的了.你可以断开了

 

   第四次挥手: 客户端回应                        好嘞 我下了

 

 

 

  1. 缓存控制?

 

    大类: 数据库缓存 + 服务器缓存 + 浏览器缓存

 

    浏览器缓存: 本地存储(localStorage  sessionStorage cookie...) + HTTP缓存   

 

    HTTP缓存: 优化页面加载效率 如果没有缓存,所有的资源必须都由服务器响应得到, 会很慢

 

    (1) 强缓存: 从服务器获取得到一个资源, 比如图片资源 会在响应时标记上一个过期时间(保质期)

        将来在使用资源前, 会判断该图片是否在有效期内, 如果在有效期内, 直接走缓存 => 强缓存  cache

 

        可以在响应头看到

          expires: Thu, 17 Jun 2032 03:00:57 GMT  制定一个具体的日期(服务器给你的)

                  到了这个过期时间, 图片就不能走缓存!!   => 绝对时间是和系统时间比对的, 系统时间是可以改的

          cache-control: max-age=315360000  指定一个相对时间 也即拿到该资源10年后 这个图片就过期了

 

          以cache-control 为主  expires为辅

 

 

    (2) 协商缓存: 如果没有命中强缓存(强缓存过期了), 浏览器就得发请求给服务器 获取资源

         前提: 本地是有xx.png的图片资源, 但是缓存过期了, 肯定要发请求获取新资源(携带过期的图片资源)

         服务器: 接收到这次请求, 判断这个图片资源是否更新过, 如果没有更新过, 还是原来那张图,此时是不需要响应图片

         客户端: 经过服务器的确认, 直接从缓存中获取, 并且要更新过期时间

 

         协商缓存有两个状态码:

            304 协商缓存成功, 服务器告诉你 图片资源没更新 你可以再用十年

                服务器响应了一个过期时间 不会响应图片

 

            200 协商失败, 服务器发现资源更新了, 就需要响应新的图片给客户端, 新的图片上也会标识过期时间

 

 

         服务器怎么判断的图片更新???

            1.图片的最后修改时间 last-modified: Fri, 10 May 2019 03:38:38 GMT

 

              将来携带过期资源时 会将last-modified 传入If-Modify-Since字段, 后端就拿到了最后修改时间, 会判断这个时间

              和服务端这个文件现在的最后修改时间 对比,  如果相同, 表示没更新, 说明图片还能用, 304 直接读缓存且设置新的过期时间

 

              缺点: 最后修改时间 最高精确到秒  如果一秒内修改了多次, 就有可能出错

 

            2.资源的唯一校验码 后端返回的, 用于标识内容的唯一性, 资源变化一定会让Etag变化, 将来我们可以拿着缓存图片的Etag

            传入If-None-Match 字段 交给后端, 对比Etag, 如果不相同, 更新过了, 之前的图片不能用了, 响应新图片给你, 200

 

 

    强缓存和协商缓存配合使用的!!!

 

 

 

 

浏览器如何解析css选择器?

    div span a { color: red; }

    你认为的: 先找到所有div, 遍历判断div下有没有后代是span, 再去遍历所有的span  找一找后代中有没有a, 如果有 就变红

    实际上: 先找所有的a 遍历, 看这个a有没有一个父代是span, 再去遍历所有span 找有没有父代是div, 如果有 就让之前那个a变红

 

    从左往后查找:

      假设你页面中有2000个div, 然后你要遍历所有的div的后代, 树形结构 每往下遍历一层 都是要付出很昂贵的代码

 

    从右往左查找:

      假设你页面中有1000个a,  找到这1000个a后  只需要往上一层一层找有没有祖辈是span(一层只需要确认一次)

 

      很显然 从右往左 效率提高了很多!! 本质上避免了遍历树形结构!!!

 

 

浏览器如何进行界面渲染?

    1. 解析html文件, 生成dom树

    2. 解析css文件, 生成样式规则

    3. 将 dom树 和 样式规则 结合, 生成渲染树

    4. 基于渲染树, 进行布局 => Layout(重排/回流)   搭架子

    5. 基于渲染树, 进行绘制 => Paint(重绘)         上色

重绘重排?

    1.结构层面, 布局变化 => 触发重排 重新layout => 重排必然重绘!!

    2.样式层面, 颜色等变化 => 触发重绘 重新paint => 重绘不一定重排

 

   实际工作: 能用重绘解决的 尽量不要触发重排!!!

   优化:

     集中修改样式 (这样可以尽可能利用浏览器的优化机制, 一次重排重绘就完成

     尽量避免在遍历循环中, 进行元素 offsetTop 等样式值的获取操作, 会强制浏览器刷新队列, 进

     利用 transform 实现动画变化效果, 去代替 left top 的变换 (轮播图等)transform变换, 只是视觉效果! 不会影响到其他盒子,  只触发了自己的重绘

     使用文档碎片(DocumentFragment)可以用于批量处理, 创建元素

 

 

 

工作过程中的git应用

    工作中 不会用 github gitee !  会用gitlab(支持搭建自己的服务器, 自建的服务器, 不依赖于第三方,更安全)

 

    以码云演示 工作中的git操作

 

 

   --------------------------------------------------------------------

    1. 创建远程仓库

    2. 创建本地项目  需要使用 git 管理

       git init

       git add .

       git commit -m '初始化'

 

       第一次提交到远程 需要 添加远程仓库别名

       git remote add origin xxxxxxxxxxxxxxx

 

       git push origin master

![杯子里有饮料

中度可信度描述已自动生成]()

   3. 本地新建 dev  test 分支, 提交到远程

   --------------------------------------------------------------------

 

   第一天上班:

 

   1. 配置ssh

      通过一个命令 ssh-keygen -t ed25519 -C "xxxxx@xxxxx.com" 生成ssh公钥秘钥

      将公钥cv到gitlab上

  

   2. 拉代码 git clone git@gitee.com:li-liqiang/test-gitee-99.git

 

   3. 基于dev开发分支 切自己的分支  220916-feature-login

 

   4. 写业务代码后, 提交代码, 提交到远程

 

   5. 切回dev分支, 本地合并220916-feature-login分支   提交到远程

 

   6. 切回test分支, 本地合并220916-feature-login分支   提交到远程

 

     (自动打包test分支的代码到测服, 然后你就让测试上场嘞)

 


 

   7. 切回master分支, 本地合并220916-feature-login分支   提交到远程

 

 

   开发环境 测试环境 验证环境(预发) 线上环境

    ![图示

描述已自动生成]()

![文本

描述已自动生成]()

一、Vue2与Vue3

Vue2、Vue3对比及Vue3特性

Object.defineProperty与Proxy

Object.defineProperty Proxy 都是用来监听数据的!!

      Object.defineProperty:

         (1) Object.defineProperty 是对于对象属性的劫持, 需要一个个劫持, 如果对象某个属性又是一个对象, 就得递归, 效率低

         (2) Object.defineProperty 对于数组的监听 是有问题的

      Proxy:

         proxy对于整个对象的劫持, 将来对象内部的任何属性发生变化 都会先经过外层proxy,无需递归, 效率很高

         proxy也可以直接监听数组的变化

vue生命周期?

   8个生命周期钩子 + 2个需要配合keep-alive使用的钩子(actived,deactived) + 1个不常用的

 

   vue2:                    vue3:

   beforeCreate             setup

   created                  setup

   beforeMount              onBeforeMount

   mounted                  onMounted

   beforeUpdate             onBeforeUpdate

   updated                  onUpdated

   beforeDestroy            onBeforeUnmount

   destroyed                onUnmounted

vue中的组件通信??

   (1) 父传子 子传父

       父传子: 通过给组件以添加属性的方式传值, 组件内部通过props接收

       子传父: 子组件内部处罚触发一个自定义时间 $emit('hhh', xxx)

              在父组件中子组件上注册对应的自定义事件@hhh='fn'

 

   (2) 事件总线(eventBus vue3被移除)   A => B

       事件总线就相当于是个中介(空的vue实例)

       1. 新建一个模块 eventBus.js

          const eventBus = new Vue()

          export default eventBus

 

       2. 在B组件中 通过中介 "收信息"

          eventBus.$on('hhh', function(val) {  ...  })

 

       3. 在A组件中, 通过中介 "发消息"

          eventBus.$emit('hhh', 123)

  

   (3) provide inject (vue3 增强了)

       用于父组件向子孙后代组件 共享数据的!!!

 

       父组件中提供数据:

         provide('money', 10000)

         provide('car', '老四莱斯')

         provide('fn', (val) => { ...... })

 

       子孙后代任意组件都可以拿到父组件提供的数据:

         const money = inject('money')

         const car = inject('car')

         const fn = inject('fn') fn(234) 子组件拿到父组件的方法后 就可以调用

 

 

   (4) childrenchildren parent $refs

       $refs     获取到指定的组件

       parent  子组件中this.parent   子组件中this.parent获取到了父组件   this.parent.money this.parent.money  this.parent.addMoney()

       children父组件中通过this.children 父组件中 通过this.children 获取到所有的子组件数组  this.children[0]this.children[0] this.children[1]

 

   (5) attrsattrs listeners 用于批量 跨层级的数据传递!!!

       场景: 一般是父组件有很多很多很多数据 要传输给孙组件   特别适用!!!!

 

       子组件将来通过v-bind='$attrs' 向下传递数据给孙组件

       子组件将来通过v-on='$listeners'  向上传递自定义事件

 

   (6) vuex

       5个核心概念:

        (1) state             存放数据

        (2) mutations         存放修改数据的方法

        (3) actions           封装异步操作 操作数据还是需要经过mutation

        (4) getters           类似计算属性

        (5) modules           分模块   namespaced: true

 

        commit('模块名/mutation名', 123)

        dispatch('模块名/action名', 123123)

 

   (7) pinia(vue3)  官方推荐的 好用!!  将来vuex5的语法 会和pinia靠拢

       核心概念:

        (1) state        存数据                     data

            state() {

               return {

                  count: 100,

                  money: 10000

               }

            }

        (2) actions      存放操作数据的方法(同步异步都可以)           methods     

            actions: {

               addCount() {

                  this.count++

               },

               addCountAsync() {

                  setTimeout(() => {

                     this.count++

                  }, 1000)

               },

               async getMoney() {

                  const res = await axios.get('/xxx/xxxxxx')

                  this.money = res.data.data.money

               }

            }

        (3) getters  计算属性

   1. 导入仓库xxx

        2. 根据仓库xxx找到对应的数据使用  找到对应的方法调用

           {{ xxx.count }}

           {{ xxx.money }}

 

           xxx.addCountAsync()

           xxx.getMoney()

           xxx.addCount()

插槽

Vue3 可以通过 usesolt 获取插槽数据

mitt.js ****适用于任意组件通信

Vue3 中移除了 $on$off等方法,所以 EventBus 不再使用,相应的替换方案就是 mitt.js

比起 Vue 实例上的 EventBus,mitt.js 好在哪里呢?首先它足够小,仅有200bytes,其次支持全部事件的监听和批量移除,它还不依赖 Vue 实例,所以可以跨框架使用

二、常用 Composition API

1.     setup是所有Composition API (组合****API ** **表演的舞台 ** **。

2.     组件中所用到的:数据、方法等等,均要配置在setup中。

3.     setup函数的两种返回值:

1.     若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。

ref 函数****

·        作用: 定义一个响应式的数据

·        语法: const xxx = ref(initValue)

o   创建一个包含响应式数据的引用对象( reference对象,简称ref****对象)

o   JS中操作数据: xxx.value

o   模板中读取数据: 不需要.value,直接:<div>{{xxx}}</div>

·        备注:

o   接收的数据可以是:基本类型、也可以是对象类型。

o   基本类型的数据:响应式依然是靠Object.defineProperty()getset完成的。

o   对象类型的数据:内部 ** **求助 ** **了Vue3.0中的一个新函数—— reactive函数。

 

reactive函数

·        作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)

·        语法: const ``代理对象``= reactive(``源对象``)接收一个对象(或数组),返回一个代理对象 Proxy的实例对象,简称proxy****对象)

·        reactive定义的响应式数据是“深层次的”。

·        内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

reactive对比ref

·        从定义数据角度对比:

o   ref用来定义:基本类型数据

o   reactive用来定义:对象(或数组)类型数据

o   备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象

·        从原理角度对比:

o   ref通过Object.defineProperty()getset来实现响应式(数据劫持)。

o   reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。

·        从使用角度对比:

o   ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value

o   reactive定义的数据:操作数据与读取数据:均不需要.value

setup的两个注意点

·        setup执行的时机

o   在beforeCreate之前执行一次,this是undefined。

·        setup的参数

o   props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。

o   context:上下文对象

§  attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs

§  slots: 收到的插槽内容, 相当于 this.$slots

§  emit: 分发自定义事件的函数, 相当于 this.$emit

watchEffect函数

·        watch的套路是:既要指明监视的属性,也要指明监视的回调。

·        watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

·        watchEffect有点像computed:

o   但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。

o   而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。

自定义hook函数

 

  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。

 

  • 类似于vue2.x中的mixin。

 

  • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

toRef

应用:   要将响应式对象中的某个属性单独提供给外部使用时。

三、其它 Composition API

1.shallowReactive 与 shallowRef

·        shallowReactive:只处理对象最外层属性的响应式(浅响应式)。

·        shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。

·        什么时候使用?

o   如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。

o   如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。

2.readonly 与 shallowReadonly

·        readonly: 让一个响应式数据变为只读的(深只读)。

·        shallowReadonly:让一个响应式数据变为只读的(浅只读)。

·        应用场景: 不希望数据被修改时。

toRaw 与 markRaw

·        toRaw:

o   作用:将一个由reactive生成的响应式对象转为普通对象

o   使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。

·        markRaw:

o   作用:标记一个对象,使其永远不会再成为响应式对象。

o   应用场景:

1.     有些值不应被设置为响应式的,例如复杂的第三方类库等。

2.     当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

5.provide 与 inject

·        作用:实现祖与后代组件间通信

·        套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据

6.响应式数据的判断

·        isRef: 检查一个值是否为一个 ref 对象

·        isReactive: 检查一个对象是否是由 reactive 创建的响应式代理

·        isReadonly: 检查一个对象是否是由 readonly 创建的只读代理

·        isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

Composition API 的优势

1.Options API 存在的问题

使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。

2.Composition API 的优势

我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组

织在一起。

五、新的组件

1.Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

2.Teleport

·        什么是Teleport?—— Teleport 是一种能够将l我们的组件html结构移动到指定位置的技术。

3.Suspense

·        等待异步组件时渲染一些额外内容,让应用有更好的用户体验

六、其他

1.全局API的转移

·        Vue 2.x 有许多全局 API 和配置。

o   例如:全局组件、注册全局指令等。

Vue3.0中对这些API注册做出了调整:

·        将全局的API,即:Vue.xxx调整到应用实例(app)上

Vue2、Vue3diff算法区别

结合到我们团队负责的支付业务场景里,由于支付业务追求极致的系统稳定性,服务不可用直接影响到客诉和资损,因此我们采用浏览器端渲染的架构。在保证系统稳定性的前提下,还需要保障用户体验,所以采用了预渲染的方式。

优化

性能优化

代码层面:

  • 防抖和节流(resize,scroll,input)。
  • 减少回流(重排)和重绘。
  • 事件委托。
  • css 放 ,js 脚本放 最底部。
  • 减少 DOM 操作。
  • 按需加载,比如 React 中使用 React.lazyReact.Suspense ,通常需要与 webpack 中的 splitChunks 配合。

构建方面:

  • 压缩代码文件,在 webpack 中使用 terser-webpack-plugin 压缩 Javascript 代码;使用 css-minimizer-webpack-plugin 压缩 CSS 代码;使用 html-webpack-plugin 压缩 html 代码。
  • 开启 gzip 压缩,webpack 中使用 compression-webpack-plugin ,node 作为服务器也要开启,使用 compression
  • 常用的第三方库使用 CDN 服务,在 webpack 中我们要配置 externals,将比如 React, Vue 这种包不打倒最终生成的文件中。而是采用 CDN 服务。

其它:

  • 使用 http2。因为解析速度快,头部压缩,多路复用,服务器推送静态资源。
  • 使用服务端渲染。
  • 图片压缩。
  • 使用 http 缓存,比如服务端的响应中添加 Cache-Control / Expires

为什么会首屏白屏

浏览器渲染包含 HTML 解析、DOM 树构建、CSSOM 构建、JavaScript 解析、布局、绘制等等,大致如下图所示

由此得出结论,因为要等待文件加载、CSSOM 构建、JS 解析等过程,而这些过程比较耗时,导致用户会长时间出于不可交互的首屏灰白屏状态,从而给用户一种网页很“慢”的感觉。

我们团队主要负责美团支付相关的业务,如果网站太慢会影响用户的支付体验,会造成客诉或资损。

  • FP:仅有一个 div 根节点。
  • FCP:包含页面的基本框架,但没有数据内容。
  • FMP:包含页面所有元素及数据。

以 Vue 为例, 在其生命周期中,mounted 对应的是 FCP,updated 对应的是 FMP。

通过以上的对比,最终选择在 mounted 时触发构建时预渲染。由于我们采用的是 CSR 的架构,没有 Node 作为中间层,因此要实现 DOM 内容的预渲染,就需要在项目构建编译时完成对原始模板的更新替换。

配置读取

由于 SPA 可以由多个路由构成,需要根据业务场景决定哪些路由需要用到预渲染。因此这里的配置文件主要是用于告知编译器需要进行预渲染的路由。

触发构建

 

 

其他

跨域

跨域是什么

跨域,是指浏览器不能执行其它网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript实施的安全限制。

简单来讲,就是从地址A加载的页面,不能访问地址B的服务(如上图)。此时地址A与地址B不同源。

所谓同源,就是域名、协议、端口均相同。

协议:http ,https 主机:域名或者ip地址(127.0.01) 端口:3000,4399

如何解决跨域

第一种:CORS 【后端】

  • 目前最主流、最简单的方案,直接让后端设置响应头,允许资源共享就ok了

第二种:JSONP 【前端+后端】

  • 曾经很流行,专治各种跨域问题
  • 需要前后端配合使用
  • 使用原理:通过script标签的src来发请求没有跨域限制来获取资源
  • 注意:JSONP只支持get请求,不支持post,请求回来的东西当做js来执行

第三种:Nginx 【后端=>反向代理】

第四种:Proxy 【前端解决:只适用于本地开发环境,上线了解决不了,直接把dist放在后端服务器中】

CORS

随着互联网的发展,同源策略严重影响了项目之间的连接,尤其是大项目,需要多个域名配合完成,因此W3C推出了CORS,即Cross-origin resource sharing(跨来源资源共享)。CORS的基本思想就是使用额外的HTTP头部让浏览器与服务器进行沟通,从而决定是否接受跨域请求。

CORS需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能。对于开发者来说,CORS通信与同源的AJAX通信没有区别,代码完全一样。浏览器在跨域访问时,会自动添加HTTP头信息,或者发起预检请求,用户对此毫无感知。因此是否支持跨域请求,关键在于服务器是否做了CORS配置,允许跨域访问。

跨域的解决办法****

遇到跨域的报错,可以分别从客户端和服务端去解决。

客户端

通过上面的分析可以知道,跨域的判断是在浏览器进行的,服务器只是根据客户端的请求做出正常的响应,服务端不对跨域做任何判断。因此如果禁用了浏览器的跨域检查,使浏览器不再对比Origin是否被服务器允许,即可发出正常的请求。

该方式需要所有客户都修改浏览器的设置,显然是不现实的,因此只在开发调试的过程中使用,如给chrome浏览器设置--disable-web-security参数。

服务端

服务端又有两种解决方式:代理转发和配置CORS

造成跨域的情况

增加代理服务器,和H5资源服务器放在同一个域名下,接口请求全走代理服务器,这样就变成了同源访问,不存在跨域访问,因此就不会存在跨域的问题。

该方式中,所有发往目标服务器的数据,都会经过代理服务器,适用于同一个公司内部不同域名之间相互访问的情况。但对于我们这个项目,由SDK发往我方服务器的数据是敏感数据,需客户端直接发往我方服务器上,不能由合作方做代理转发,因此不能使用此种方式。

使用此方式还需注意一点,应关注代理服务器的性能,代理服务器的性能应与后端的目标服务器的性能相匹配,否则代理服务器会成为整个系统的性能瓶颈。

 

![图示

描述已自动生成]()

配置CORS

在目标服务器上配置CORS响应头,这样浏览器经过对比判断之后,就可以发起正常的访问。

目标服务一般是由软负载和应用服务组成(如常见的apache+jboss,nginx+tomcat等组合),在软负载和应用上都可添加CORS响应头。

如在apache的httpd.conf中添加如下配置:

或者nginx的配置中增加如下配置:

此方式的优点是不用修改应用代码,缺点是不能做细粒度的编程,从而做到细粒度的控制,如根据请求参数的不同而返回不同的结果。

另一种方式,就是修改应用代码。通常是在服务器代码中增加filter,在filter中在HTTP响应头添加相应的字段

由于是通过代码控制,因此可以实现细粒度的控制,在解决跨域问题的同时,可以满足复杂的业务需求。

总结

  • 跨域是由浏览器的同源策略造成的,所谓同源,即域名、协议、端口均相同。
  • CORS(跨来源资源共享),通过添加HTTP头信息,使浏览器判断是否可以发起跨域访问。
  • 浏览器将跨域请求分为两类:简单请求和非简单请求。简单请求采取先请求后判断的方式,非简单请求采取预检请求的方式判断是否允许跨域访问。
  • 解决跨域通常采用服务端代理转发和配置CORS两种方式。

TS

TS有哪些好处?

1.ts是js的超级,给js增加了可选的静态类型和基于类的面向对象的编程

2.ts在编译时会有错误提示,js在运行时才能暴露错误

3.ts是强类型语言,强制定义各种数据的类型,可读性强

4.ts有很多方便的特性,比如可选链

  • 增强代码的可维护性,尤其在大型项目的时候效果显著
  • 友好地在编辑器里提示错误,编译阶段就能检查类型发现大部分错误
  • 支持最新的JavaScript新特特性
  • 周边生态繁荣,vue3已全面支持 typescript
  • 缺点
  • 需要一定的学习成本
  • 和一些插件库的兼容并不是特别完美,如以前在 vue2 项目里使用 typescript就并不是那么顺畅
  • 增加前期开发的成本,毕竟你需要写更多的代码(但是便于后期的维护)

ts 和 js 的优缺点

·        ts 是 js 的超集,即你可以在 ts 中使用原生 js 语法。

·        ts 需要静态编译,它提供了强类型与更多面向对象的内容。

·        ts 最终仍要编译为弱类型,基于对象的原生的 js,再运行

可选链常用场景及优势

可选链操作符在前端开发中的使用场景是处理嵌套对象的属性或方法访问,并且它的优势在于简化代码、避免空引用错误以及提高代码的可读性。它是一个强大的工具,可以提高开发效率并减少错误。

TS内置工具类型

Required、Partial、Exclude、Extract、Readonly、Record、Pick、NonNullable、ReturnType、Parameters、InstanceType

  1. Required

将类型的属性变成必选

  1. Partial

与 Required 相反,将所有属性转换为可选属性

  1. Exclude

Exclude<T, U> 的作用是将某个类型中属于另一个的类型移除掉,剩余的属性构成新的类型

  1. Extract

和 Exclude 相反,Extract<T,U> 从 T 中提取出 U。

  1. Readonly

把数组或对象的所有属性值转换为只读的,这就意味着这些属性不能被重新赋值。

  1. Record

Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。

  1. Pick

从某个类型中挑出一些属性出来

  1. NonNullable

去除类型中的 null 和 undefined

  1. ReturnType

用来得到一个函数的返回值类型

  1. Parameters

用于获得函数的参数类型所组成的元组类型。

  1. InstanceType

返回构造函数类型T的实例类型

接口与类型别名的区别

实际上,在大多数的情况下使用接口类型和类型别名的效果等价,但是在某些特定的场景下这两者还是存在很大区别。

接口和类型别名都可以用来描述对象或函数的类型,只是语法不同****

都允许扩展****

相同点


  • interface 用 extends 来实现扩展
  • type 使用 & 实现扩展

不同点

  • type可以声明基本数据类型别名/联合类型/元组等,而interface不行
  • interface能够合并声明,而type不行
  • 如果存储的元素数据类型不同,则需要使用元组  合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值

项目中

接口类型规范、属性规范

一般来说,Canvas 更适合绘制图形元素数量较多(这一般是由数据量大导致)的图表(如热力图、地理坐标系或平行坐标系上的大规模线图或散点图等),也利于实现某些视觉 特效。但是,在不少场景中,SVG 具有重要的优势:它的内存占用更低(这对移动端尤其重要)、并且用户使用浏览器内置的缩放功能时不会模糊。

选择哪种渲染器,我们可以根据软硬件环境、数据量、功能需求综合考虑。

在软硬件环境较好,数据量不大的场景下,两种渲染器都可以适用,并不需要太多纠结。

在环境较差,出现性能问题需要优化的场景下,可以通过试验来确定使用哪种渲染器。比如有这些经验:

在需要创建很多 ECharts 实例且浏览器易崩溃的情况下(可能是因为 Canvas 数量多导致内存占用超出手机承受能力),可以使用 SVG 渲染器来进行改善。大略的说,如果图表运行在低端安卓机,或者我们在使用一些特定图表如 水球图 等,SVG 渲染器可能效果更好。

数据量较大(经验判断 > 1k)、较多交互时,建议选择 Canvas 渲染器。

我们强烈欢迎开发者们反馈给我们使用的体验和场景,帮助我们更好的做优化。

注:当前某些特殊的渲染依然需要依赖 Canvas:如炫光尾迹特效带有混合效果的热力图等。