海绵宝宝学习前端

前端学习+面试

HTML+CSS

1.标签

input 标签

css属性

outline:是border外面的一层,input输入框获取焦点的时候出现的就是这个

事件

@input :当键盘输入时,触发input事件,event.detail = {value}
@compositionstart 先于input事件触发。开始输入中文的时候会触发一次compositionstart事件,中文输入过程中不会再出发compositionstart事件
@compositionend 输入中文完成触发compositionend 事件

table标签

table标签本身没有滚动条,要用个div抱起来,或者换句话说目前只有block属性的才有滚动条出现

textarea

禁止拖动框改变大小。
q:多行文本在Chrome,Safari和FireFox渲染的效果不同,可以拖动右下角图标改变大小,但是想禁止拖动框改变大小,固定文本框的大小。
sovle方法:
1.禁止拖动框改变大小
在这里插入图片描述
2.最大的高度=高度
在这里插入图片描述

2.选择器

1.基础选择器

id>类>标签>通配符

2.多个选择器混用

后代 :空格
子代: >
交集:没有间隙 既是又是
并集:,

3.伪类选择器

hover
结构伪类

注意点:作用在子元素身上,不是父元素

li:first-child{}//父元素的第一个并且是li 才能够选中,否则不选中
li:last-child{}
li:nth-child(n){}
li:nth-last-child(n){}

li:nth-child(n){}//先找到父元素的第n个元素,并且同时必须是li元素
li:nth-f-type(n){}//父元素中提取li元素,并选中第n个li元素

链接伪类选择器(针对a标签)

LVHA
link
visited
hover
active

焦点伪类选择器(正对input标签的)

当input标签获取焦点

    <style>
        input:focus {  
            background-color: lightblue;
        }
    </style>
属性选择器

4.属性选择器

3.字体,文本样式,背景,盒子,伪元素

3.1字体

3.2文本样式

word-break
white-space

word-break 文本打断

在这里插入图片描述

white-space属性

是什么:是用来定义元素内的空白该如何处理
在这里插入图片描述

块级元素且固定的宽高:

一般情况下,块级元素都是默认自动换行(这的元素只指块级,table和display:table还没有研究),所以块级元素内部的文本会自动换行,(无论中英文,就是英文单字都会被截断换行。)
1.中英文文本内容一行超出宽度会自动换行,换行超出高度溢出。默认自带:white-space:normal 自动换行属性
在这里插入图片描述jiceh
在这里插入图片描述
链接: link white-space知识点

问题:
1.不想换行:

white-space:nowrap。

2. 不换行,超出宽度,省略号

2.1.单行文本不换行
3个属性必须设置
在这里插入图片描述
text-overflow属性必须配合这两个属性一起使用才生效。

2.2.多行文本超出规定行数显示省略号。
5个属性要必须设置。
区别:单行不换行省略。
overflow和text-overflow不变。white-space不需要。
变化3个:父盒子:变为弹性盒子。第几行省略,子元素排列方式
在这里插入图片描述
在这里插入图片描述

display-cell 文本内容

3.强制换行:

3.3盒子

1.盒子width和height设置

盒子是块元素
1.盒子没有设置宽高:
盒子宽:是父元素的宽,默认撑开一行(如果父元素设置了padding,盒子的宽度就是父元素盒子内容的宽度)和子盒子没有关系,
盒子高:没有内容就是0,有内容靠内容撑开。.
2.盒子设置了宽高:
盒子宽高设置

2父子盒子之间关系

1.父,子盒子都没有设置宽高
父盒子的宽:父盒子的父元素的内容的宽
父盒子的高:0
子宽:父盒子的内容宽
子高:0
2.父设置宽高,子没有设置宽高
父:设置了宽高
子:子高:0或者是子里面的内容撑开
3.父子都设置宽高:
子盒子的宽高大于父盒子。
子盒子会溢出父盒子。
4.父没有宽高,子有宽高
1.父:
父宽:之和父盒子的父元素有关系,默认一行。
父高:和子元素有关系,由内容撑开

3.盒子和文本内容

盒子中的文本内容如果超过盒子的宽高,就会溢出。除非盒子设置了overflow属性
1.当文本内容超过盒子的宽度:
一般会自动换行,但是如果是没有空格的英文会自动识别成一个字符就不会换行
2.当文本超过盒子高度:
直接溢出盒子的高度。

盒子总结

盒子没有设置宽高:
盒子:宽:由盒子的父元素宽决定
高:由盒子里面子元素的内容撑开
盒子设置了宽高:
里面的内容超出盒子的宽高会溢出。
如果里面的内容脱离标准流,父盒子不会被撑开。
盒子的margin注意点
两个盒子之间:
上下margin合并(产生塌陷问题:外边距塌陷和包含塌陷)
左右的margin不合并

3.4 伪元素

4.位置(定位,浮动,修饰,布局)

4.1布局

常见布局:静态布局,流式布局(又称百分百布局),弹性布局,自适应布局,响应式布局

静态布局

网页的元素和内容的大小和位置都是固定的,无论浏览器窗口的大小如何改变,网页的布局不会发生任何变化。
全部用px,窗口大小无论怎么变化网页不会变化

流式布局(又称百分百布局)

页面元素的大小和位置是相对的,页面内容会随着浏览器窗口的大小而自适应地调整,但是页面元素的相对大小和位置比例保持不变。
用px+百分百制作。
当页面窗口变化,百分百的部分会随着页面窗口的变化而变化。会变得很大也可能变得很小,但是元素相对于窗口的位置以及大小都不会变,元素和窗口就是等比例缩放的意思。
链接: 两栏布局

弹性布局

元素的大小和位置会根据浏览器窗口大小进行调整,同时也可以使用弹性盒模型(Flexbox)或栅格系统(Grid)等技术实现灵活的布局。
使用flex和grids技术实现。

自适应布局

提前设置好不同的布局格式,根据设备的屏幕尺寸,自动选择最适合的布局尺寸进行展示。

响应式布局

区别自适应:不是提前设定好的布局格式,是动态生成的。
响应式布局则是指通过使用CSS媒体查询等技术,根据设备的屏幕尺寸和分辨率来动态地调整网页元素的样式、排列和布局等,以实现最佳的显示效果。在响应式布局中,网页元素的布局和样式是根据不同的屏幕尺寸和设备类型来自适应地调整的,从而能够更好地适应各种设备和屏幕。

总结

在这里插入图片描述

4.2 能改变位置的css和布局相关的属性

浮动:float,定位position,flex,vertical-align ,grid布局

flex(具体属性见面试css flex布局)

使用flex,浮动和vertical失效

grid 布局

链接: grid 布局

注意点
1.父子是亲父子才有效,对孙子无效
在这里插入图片描述

容器属性:

在这里插入代码片

1.display:grid(块) display: inline-grid(行内块):注意,设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效。
在这里插入图片描述
2.定义列行单元格的大小 grid-template-columns属性定义每一列的列宽,grid-template-rows属性定义每一行的行高。
规定的方式有:
(1)直接写px或者百分比,有几列写几个
(2)用repeat()函数
函数 repeat()接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值单元格的大小。
第一个参数:可以写数字,也可以写auto-fill(使用情况:单元格大小固定,容器大小不确定,且要单元格填充满容器。代表单元格大小固定,自动填充容器,有多少填充多少个单元格)
第二个参数可以写不知只一个
在这里插入图片描述在这里插入图片描述
(3)fr 比例单位,列于列之间的大小关系看比例,且可以和可以和px合用,类似flex的用法
在这里插入图片描述
在这里插入图片描述
(4)minmax()函数,表示一个范围,可用于列宽也可用于行高
两个参数,
第一个参数最小值
第二个参数最大值,可用px,fr
在这里插入图片描述
(5)auto
在这里插入图片描述

3.定义行列之间的空格
grid-row-gap 属性,grid-column-gap 属性,grid-gap 属性
单位:px
在这里插入图片描述

4.每一个单元格定义名字
== grid-template-areas== 属性
网格布局允许指定"区域"(area),一个区域由单个或多个单元格组成。grid-template-areas属性用于定义区域。
在这里插入图片描述

  1. grid-auto-flow 属性 == 容器子元素的排列顺序==,先行后列默认,
    在这里插入图片描述

6 定义单元格里面内容,在单元格的位置
justify-items 属性,属性设置单元格内容的水平位置(左中右)
align-items 属性,属性设置单元格内容的水平位置(左中右)
place-items 属性
在这里插入图片描述
7.整个内容区域在容器里面的位置
justify-content 属性,整个内容区域在容器里面的水平位置(左中右)
align-content 属性,属性是整个内容区域的垂直位置(上中下)。
place-content 属性 合写 先垂直后水平
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

容器里面项目属性:

  1. 关于指定单元格位置:2个方法:
    1.通过指定边框
    2.通过定义的区域名称
    法1.项目的位置是可以指定的,具体方法就是指定项目的四个边框,分别定位在哪根网格线。
    在这里插入图片描述
    合并简写形式:
    在这里插入图片描述

值:数字(代表从左往右从上往下第几个线)
或者是网格线名称(来源:1.grid-template-area给每个单元格起名字,同时影响到网格线的名字。2.grid-template-columns在定义列宽的时候也可以定义网格线名字)
在这里插入图片描述

在这里插入图片描述
法2:
grid-area属性指定项目放在哪一个区域。
在这里插入图片描述
2.
justify-self 属性,
align-self 属性,
place-self 属性
在这里插入图片描述

5 。转换(transform属性:平面:位移,旋转,缩放。空间:位移,旋转,缩放)

5.1平面转换
5.2空间转换

5.1 平面转换:位移,旋转,缩放

位移:

单位:
1.px
2.%(相对已自己的宽高)

在这里插入图片描述

//平面没有Z方向
transform:translateX(50px)
transform:translateY(50px)
transform:translateZ(50px)
transform:translate(50px,50px)
旋转:

正:顺时针
负:逆时针
单位:deg
用法: 1.改变旋转角度
2.改变旋转中心

//旋转
transform:rotate()
//改变旋转中心:
transform-origin: top/left/right
transform-origin: 数字+px
transform-origin: 百分比

缩放

单位:没有单位,>1 放大 ,<1缩小

transform:scale(0.1)

5.2 空间转换

空间位移

Z轴平移:属于立体效果(近大远小),默认情况下网页是不支持透视,如果需要看见效果必须要设置网页的视距。
父元素:设置perspective: 800px;
子盒子:transform:tranlatez(200px)

perspective: 800px;
transform:translate3d(x,y,z)
空间旋转

transform-style: preserve-3d;
transform:rotate3d()

空间缩放

动画

5 动画(说白了控制元素移动)

链接: 动画

5.1 过渡(4个属性,加1和合写)

使用步骤分两步

1.第一步:触发条件以及过渡的结束状态(当条件触发过渡开始,当条件结束,属性会按照原来的方式变回初始状态,不是一下子就变成初始状态)
2.第二步:定义过渡的属性

指定需要过度的属性名 : transition-property 如:all(所有属性)、width、height、background、…

1.多个属性间使用,隔开( transition-property: width,height;)
2.如果所有属性都需要过渡,则使用all关键字
3.大部分属性都支持过渡效果,注意过渡时必须是有效数值向另外一个有效数值进行过渡,比如auto向0过渡就不是一个有效值

transition-duration:过渡效果执行的时间

1.时间单位:s 和 ms 1s=1000ms
2.可以分别指定时间(transition-duration: 100ms,2s;)分别指定时间是因为可以指定多个属性同时变化,分分别指定的时间和transition-duration中分别指定的元素的css属性一一对应

transition-timing-function:规定过渡的速度曲线

1.ease 默认值 ,慢速开始,先加速,再减速
2. linear 匀速运动
3.ease-in加速运动
4.减速运动ease-out
5.先加速在减速ease-in-out

transition-delay;规定过渡何时开始

单位是s

transition简写模式 :

ransition-property transition-duration transition-timing-function transition-delay
可以同时设置过度相关的所有属性,只有一个要求,如果要写延迟,则两个时间中第一个是持续时间,第二个是延迟

.box{
//单个属性
transition:background 0.5s ease-out 0s;
//多个属性  多个属性之间用逗号隔开
transition:background 0.5s ease-out 0s,color 0.5s ease-out 1s
}

触发过渡的方式

常见的就是伪类触发:hover,:active,:focus,:checked等。还有例如@media媒体查询,根据设备大小,横屏竖屏切换时触发。还有,如click,keydown等JS事件触发,页面加载也能触发就不一一列举了。

5.2 动画

使用步骤分两步:

1.第一步@keyframs 定义动画
2.第二部定义动画的运行方式

1.animation-name:指定要对当前元素生效的关键帧的名字(keyframs定义的)
2.animation-duration:指定动画的执行时间
3.animation-timing-function:跟transition-timing-function用法一样,step是值每一帧之间的步数
4. animation-iteration-count:指定动画执行的次数

默认: animation-iteration-count:infinite;(无限执行)

5.animation-direction:指定动画运行的方向

normal 默认值 从from向to运行 每次都是这样
reverse 从 to 向 from 运行 每次都是这样
alternate 从 from 向 to 运行 重复执行动画时反向执行 (一开始从from到to在结束状态的时候,to到from来回执行。这个要配合 animation-iteration-count:infinite;(无限执行)一起用)
alternate-reverse 从 to 向 from运行 重复执行动画时反向执行

  1. animation-play-state:设置动画的执行状态

可选值:
running 默认值 动画执行
paused 动画暂停

7.animation-fill-mode:指定动画的填充模式

可选值: none 默认值 动画执行完毕元素回到原来位置 forwards 动画执行完毕元素会停止在动画结束的位置 backwards
动画延时等待时,元素就会处于开始位置 both 结合了 forwards 和 backwards

8.animation-delay:设置动画的延时

动画与过渡的区别:

1.过渡需要一个触发,动画不需要触发,只要定义完毕就行。

5.3 变形

5.4 旋转

5.5 缩放

6.常见属性积累

contenteditable:true(开启可编辑模式)/false
pointer-events: none; 点击穿透当层

画一个table样式什么方法

1.table组件
2.display:table
3.ui li ,li浮动

两个display-inline的元素在同一行但是位置错落了

链接: 使用display: inline-block出现错位

原因:设置display-inlineblock,两个元素默认baseline对齐,就有可能造成错落,因为两个元素的基线可能不一样,
解决方法:1. vertical-align:top等  
         2.干脆不用display-inlieblock布局,换其他的方式

100%的用法

line-height:: 可作用在块元素,行内元素,行内元素,是告诉作用的标签以及标签中的子标签,只要有文本,文本高度是多少。
line-heighr:100% 这个100%吃的是当前标签的font-size大小,如果没,网父层吃,不会往子吃。
text-align:center 居中:作用于有宽度的行内块或者块元素,如果作用在行内元素上无用(行内元素也不能设宽度)。
margin-top:50%,这个50%吃的是父层的宽度,是宽度的50%,父层没有,再往上吃。 position:relative
top,left 移动百分比位置是移动自己的宽高 position:absolute top left 移动位置是移动
position:absolute 之后,盒子width:100%,吃的是父级且有定位,如果没有就是body宽度
transform:tanslateX() 百分之是自己的百分之多少

bfc

bfc是什么

块级格式上下文。
内部布局规则:垂直方向一个接一个
每一个BFC区域只包括其子元素不包括其子元素的子元素。

bfc用处

在浏览器页面中创立了一个独立渲染的区域,bfc内部的元素无论怎么样都不会影响到bfc外面的元素。

bfc如何产生

脱标+display+overflow

    1.浮动的元素,除了float:none
    2.定位:absolute和fixed  
    3.diplay:inline-block,table(行内块元素),flex(弹性布局)
    4.overflow:不是visible,
                       hidden(推荐)
用处1:清除浮动带来的影响

问题:父盒子没有设置宽高,子盒子浮动,父盒子不会被撑开。
bfc内部的盒子就算是浮动的也参加计算
所以:清除浮动,父元素设置为bfc,子盒子就算浮动也要进入计算,所以父盒子还是被子盒子撑高了。

用处2:解决margin塌陷

1.外边距塌陷:将两个盒子分别放在两个bfc中。即将两个盒子通过两个bfc盒子进行隔离。
2.包含塌陷:将父盒子变成bfc盒子。子盒子就不会和父盒子产生塌陷。父盒子内的子元素不会影响到父盒子的外面,以父盒子的border为界限。子元素不会影响到父盒子border以外的东西。

css引入

css引入三种:内嵌,外联,行内式

1.行内式

标签内部 style =“”

2.内嵌:

head标签内部style标签
在这里插入图片描述

3.外联:

外联有两种方法link与@import

3.1 link head标签中link标签

在这里插入图片描述

3.2 @import head标签中style标签@import

在这里插入图片描述
在这里插入图片描述

link和@import区别:5点
1、从属关系:link是html的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等;而@import是css的语法,只有导入样式表的作用。
2、加载顺序:页面被加载时,link会和html同时被加载而;@import引入的 CSS 将在页面加载完毕后被加载。(@import是再dom树渲染完毕之后,才加载的)
3、兼容性:@import是 CSS2.1 才有的语法,所以只能在 IE5以上 才能识别;而link是 HTML 标签,所以不存在兼容性问题。
4、DOM:javascript只能控制dom去改变link标签引入的样式,而@import的样式不是dom可以控制的。(@import不能通过js'代码控制,link引入的标签是可以的。)
5、link方式的样式权重高于@import的权重。
link和@import使用场景区别

@import是依赖css的,存在一定的兼容问题,并且根据浏览器渲染机制来说,他在dom树渲染完成后才会渲染,并且不能被js动态修改。相比之下link兼容性较好,且dom元素的样式可以被js动态修改,又因为link的权重高于@import,
所以 @import适用于引入公共基础样式或第三方样式,link适用于自己写的且需要动态修改的样式

简述src和href的区别

相同点:都是引用外部资源
不同点:

hrefsrc
link,a标签使用script,imag,video,audio等标签使用
将当前元素和外部资源建立联系,当浏览器解析到href时,解析不会停止src用外部资源替换当前元素,当浏览器解析到src时,会暂停浏览器的解析,去下载外部资源。所以再用script引入js文档的时候,要写在最后,目的是最后去去加载js文档

行内元素,行内块,块元素

1.行内元素:
2.行内块元素:
3.块元素:

行内元素行内块元素块元素
一行多个一行多个独占一行
不可设置宽高,宽高就是内容大小,行内元素的宽高是被内容撑开,设置宽度,高度,以及行高,和text-align都是无效的可设置宽高可设置宽高
水平方向上的padding和margin可以设置,垂直方向上的无效水平方向上的padding和margin可以设置,垂直方向上的无效margin,padding都能设置
行内元素中只能放行内元素标签或者纯文本==(a标签除外,a里面不可以放自己)==块级标签内部能放块,行内块,行内元素
标签a,span,伪元素,img(可以当行内块使用)input,textarea,button,selectdiv,p,h,ul li,ol li,dldtdd

JS

promise

  class Promise {
    constructor(executor) {
      this.PromiseState = 'pending'
      this.PromiseResult = undefined
      this.calbackFn ={}
      const _resolve =value => {
        if(this.PromiseState == 'pending' ) return
        this.PromiseState = 'fulfilled'
        this.PromiseResult = value
        if(this.calbackFn.onfulfiled){
          this.calbackFn.onfulfiled()
        }
      }
      const _reject =value => {
        if(this.PromiseState == 'pending' ) return
        this.PromiseState = 'rejected'
        this.PromiseResult = value
        if(this.calbackFn.onreject){
          this.calbackFn.onreject()
        }
      }
      try{
        executor(_resolve,_reject)
      }catch (err){
        _reject(err)
      }
      executor(_resolve,_reject)
    }
    then(onfulfiled,onreject){
      if(!(onfulfiled instanceof Function)) onfulfiled = value=> value
      if(!(onreject instanceof Function)) onreject = reason=> {return throw reason}
      return new Promise((resolve,reject)=>{
        const _commod = function (callBack){
          setTimeout(()=>{
            try {
              const value = callBack(this.PromiseResult)
              if(value instanceof Promise){
                value.then(v=>{
                  resolve(v)
                },r=>{
                  reject(v)
                })
              }else{
                resolve(value)
              }
            }catch (err){
              reject(err)
            }
          })

        }
        if(this.PromiseState == 'fulfilled') _commod.call(this,onfulfiled)
        else if(this.PromiseState == 'rejected') _commod.call(this,onreject)
          //当this.PromiseState 状态为pending的处理
        else{
          this.calbackFn ={
            onfulfiled:_commod.bind(this,onfulfiled),
            onreject:_commod.bind(this,onfulfiled)
          }
        }
      })
    }
  }
  const p1 = new Promise((resolve,reject)=>{
    resolve(1)
  })
  p1.then(value =>{
    console.log(value)
  },reason =>{})

水平垂直居中

1.弹性盒子

水平居中 justfy-content:center
垂直居中 align-items:center

2.行内块,行内元素

水平居中text-align:center
垂直居中 line-height = height

3.盒子

必须直到子元素宽 :子绝父相 + margin:-50%
必须直到子元素宽 :子绝父相 + transform:translate

4.table (不推荐)

5.grid(不如flex)

​ 给父级设display:grid;
​ 给子元素设align-self: center;justify-self: center;

拷贝

深拷贝浅拷贝
浅拷贝
object.assign({},被拷贝) 第一层是深拷贝,第二层是浅拷贝
[…arr]扩展运算符
slice() 截取
实现深拷贝:

3中方法:1. JSON.stringify 和 JSON.parse
2. 递归嵌套拷贝
3. lodash.cloneDeep(第三方库)

  • 1.JSON.Stringfy与JSON.parse

缺点:函数不会被拷贝

let arr1 = [1, {name:123},3]
let arr2 = JSON.parse(JSON.stringify(arr1))
arr1[0]= 5
arr1[1].name = 'hjashd'
console.log(arr1,arr2)

在这里插入图片描述

  • 2.递归
function deepClone(obj={}){
  //参数不是数组或者对像直接return
  if(typeof obj !=='object') return
  let cloneObj = obj instanceof Array?[]:{}
  // let cloneObj = Array.isArray(obj)?[]:{}
  for (let key in obj){
     if(obj[key]&&typeof obj[key] == 'object') {
       cloneObj[key] = deepClone(obj[key])
     }else{
       cloneObj[key] = obj[key]
     }
  }
  return cloneObj
}

缓存

在这里插入图片描述

http缓存

什么是http缓存:

在这里插入图片描述

为什么要缓存:加快网站加载速度

在这里插入图片描述

怎么缓存:如下

http缓存:强制缓存,协商缓存

强制缓存:响应头设置cache-control:设置事件

在这里插入图片描述

协商缓存:返回资源标识:last-modified etag
在这里插入图片描述

协商缓存强制缓存关联

在强制缓存失效后,浏览器开始协商缓存
在这里插入图片描述

浏览器缓存 localstorage,sessionStorage,cookie

localstoragesessionStoragecookiesession
存储位置本地存储,客户端浏览器本地存储,客户端浏览器本地存储,客户端浏览器服务器
存储大小5-1054kb没有限制
存储内容键值对只能存储字符串类型键值对只能存储字符串类型字符串没有限制
生命周期永久除非删除浏览关闭,或者当前会话关闭设置日期的自行设定
跨域同源不能跨域同源不能跨域

原型和原型链

原型链:
是什么:对象顺着==proto==的属性想上找,形成了链条,就是原型链

继承

原型链继承,构造继承,组合继承,寄生组合继承 类继承

原型链继承:父构造函数的实例 = 子构造函数的原型对象

function father(data){
this.name = 'xxxx
this.data = data
}
function son(){}
son.prototype =  new father()
son.prototype.constructor = son //将子函数原型对象的constuctor重新赋值

var sonObject = new Son()

优: 继承
缺: 1.在子类实例化(即var sonObject = new Son())的时候不能向父类构造函数传参
2.

构造继承:只将父构造函数的属性通过call继承
优:
缺点:1.没有父构造函数原型对象的方法即father。prototype的方法
2. 方法不复用,son1的say方法和son2的say方法不是同一个,是不同的两 个,只是样子一样,占空间(new 会开辟一个新空间)

function father(){
this.say = function (){
console.log()
}
}
function Son1(name) {
	Father.call(this);
	this.name = name || 'Tom';
}
function Son2(name) {
	Father.call(this);
	this.name = name || 'Tom';
}

组合继承:原型链继承和构造继承结合。
子构造函数的原型对象来源父构造函数的实例对象(原型链继承)
子构造函数的属性来自父构造函数的属性(构造继承)

function f ( name){
this.name  = name
}
function son (name,age){
f.call(this,name)
this.age = age
}
son.prototype = new f()
son.prototype.constructor = son //修正constructor


优点:
缺点:f.call和new f () 生成了两份父实例属性。【解决方法:父构造函数的原型对象 = 子构造函数的原型对象,这就就是寄生组合继承的思路,通过object。create()实现
优化:减少生成多余属性
son.prototype = f.prototype
缺点:父子的原型对象是同一个,任意修改一个另外一个也会变,

寄生组合继承

function father (name){
this.name = name
}

function son (name){
father.call(name)
}


//关键一步  object.create 
son.prototype = object.create(father.prototype)
son.prototype.constructor = son 

在这里插入图片描述

闭包

内层函数使用外层函数的变量

function f (){
	var count = 0
	return function s (){
		count++
	}
}

好处:
1.隔离作用域,保护私有变量
2. 延长变量的生命周期
3.可以使用回调操作外层函数的内部变量(即操作函数的内部)
坏处:无法自动销毁,容易引起内存泄漏

let const var 区别

let 块级作用域 不存在变量提升 值可更改
cosnt 块级作用域 不存在变量提升 值不可更改
var 全局作用域 变量提升 值可更改

箭头函数与Es5函数区别

区别箭头函数es5函数
this没有this,this是上下文的this有this
构造函数不能当构造函数,就是不能 new可以当构造函数
argument无arguments对象

call apply bind

call、apply、bind的区别
call、apply、bind相同点:都是改变this的指向,传入的第一个参数都是绑定this的指向,在非严格模式中,如果第一个参数是nul或者undefined,会把全局对象(浏览器是window)作为this的值,要注意的是,在严格模式中,null
就是 null,undefined 就是 undefined
call和apply唯一的区别是:call传入的是参数列表,apply传入的是数组,也可以是类数组 bind和call、apply的区别:
bind与call,applay区别:返回的是一个改变了this指向的函数,而call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
注意:1.当 bind 返回的函数 使用new作为构造函数时,绑定的 this 值会失效,this指向实例对象,但传入的参数依然生效。(new调用的优先级 > bind调用)
2.bind的多次绑定只有第一次是有效的

是什么:

call:1.改变this指向,2.直接调用函数,3.假如传参(参数不是)

事件循环

链接: 事件循环

前置知识:
进程:是内存,程序代码运行的地方
线程:运行代码的人。
一个进程有多个线程
js是一个单线程的语言。

是什么:事件循环是主线程渲染的工作方式。
事件循环过程:

  • 1.执行栈:所有同步任务都在主线程上执行,形成一个执行栈(调用栈)
  • 2.消息队列:异步任务的回调事件塞入消息队列
    主线程不停的工作,将异步任务放在其他线程,当主线程工作完毕,去消息队列取回调函数进行,完成之后再去消息队列,直到消息队列的任务全部完成。
    消息队列优先级:微队列(promise回调,nextTicK)>交互队列(存放用户操作后产生的事件处理任务)>延时队列((宏任务:setTimeout、setInterval、postMessage,ajax请求,settimeoutt)存放计时器到达后的回调任务)

js 数据类型以及相应的处理

数据类型:基本数据类型6种和复杂数据类型

1.基本数据类型

6种
number,string,boolean, undefined,null,symbol(es6)

undefined与null 区别:

undefined是一个变量最原始的状态值,非人为操作
null是人为地置空
undefined == null

判断是否为null:if(i === null)

symbol

1.是什么:用来标识独一无二的值
2.为什么:
运用的场景:
(1)使用第三方插件的,需要自定义的时候,有可能定义的属性和方法与第三方插件原有的属性方法重合,就会将其覆盖。为了避免这种情况的发生, 框架的作者或者我们就可以使用Symbol作为属性或者方法的名称
3.怎么用:
let xxx=Symbol(‘标识字符串’);

2.复杂数据类型

3.数据类型相关操作

1.判断数据类型(5种方法)*****

注意:以下方法判断变量是否是数字类型是有问题:
在判断一个对象之前,先Number(变量),强行转化为数字类型,会导致接下来所有判断全是number类型,要注意,在判断类型之前是否有强转类型的操作

链接: 判断JS数据类型的五种方法
Array.isArray(对象名)
在这里插入图片描述

  1. typeof
    总结:
    1.typeof 可以对JS基础数据类型(数组和对象都返回的对象形式做出准确的判断(特殊:除了null返回的是object(原因:js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息,000:对象,null:所有机器码均为0,所以typeof将null认为是对象。)),
    2.对于引用类型返回的基本上都是object(原因:所有对象的原型链最终都指向了Object,Object是所有对象的祖宗

所以能返回6个(没有数组):number、string、boolean、function、undefined、object。
在这里插入图片描述
2. instanceof

1.用来判断复杂数据类型,返回true和false。不能用来判断基本数据类型(原因:intance原理是原型链。通过判断构造函数的原型对象和实例的__proto__属性是不是同一个来确定。)
arr intanceof Array

  1. 总结

1.判断 string,boolean,number 用typeof
2.判断数组,instanceof Object.prototype.toString Array.isArray()
3.判断对象 intanceof Object.prototype.toString

2.数据类型之间的转换(基本数据类型之间的转换)只有三种*****

1.转换为boolean值
2.转换为数字
3.转换为字符串

代码返回值
转换为boolean类型Boolean(变量)在这里插入图片描述
转换为number类型在这里插入图片描述Number 返回值只有三种:0,数字,NaN。 parseInt的返回值0,数字,不会返回NaN在这里插入图片描述
转换为字符串类型String(变量)      变量.toString(2) 10进制转2进制
判断数组是否为空

可用方法

数组.length

不可用

数组 == 【】 这个得到的结果只是false , == 用于数值之间的比较

数组去重
//法1 双for循环
//法2  set set成员唯一,就是没有重复值的数组。
let arr = [...new Set(arr1)]

数组是否包含某个元素

方法一: arr.indexOf()
方法二: for循环结合if判断
方法三: arr.find(callback)
在这里插入图片描述

方法四: arr.includes() 数组中含有某值返回true,没有返回false。ES6新方法
在这里插入图片描述

js中的this

this指向就是该函数的运行环境,this在函数创建的时候就创建了,但是如果该函数没有被调用等等,只是创建了,该this是没有指向的,只有该函数被调用,this才会指向调用者。
1.普通函数

普通函数:关于this,谁调用就指向谁,没有调用者,就指向全局对象window。

2.箭头函数

箭头函数没有this,捕捉箭头函数外层执行环境为this

3.构造函数中的this

构造函数中的this指向构造函数下创建的实例。
在这里插入图片描述

构造函数与原型链原型对象

1. 构造函数

1.构造函数是什么

构造函数是一个函数。

2.为什么要用构造函数

目的:为了创建相似的对象
对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的特征(属性)和行为(方法),此时会产生很多重复的代码,而使用构造函数就可以实现代码复用。

3. 怎么用构造函数

两步:
1.定义构造函数(注意:函数名第一个字大写默认写法,)
2.new+构造函数
注意:当一个函数创建好以后,我们并不知道它是不是构造函数,即使像上面的例子一样,函数名为大写,我们也不能确定。只有当一个函数以 new 关键字来调用的时候,我们才能说它是一个构造函数

new的执行过程发生的四件事

1.在内存中开辟一个空对象,名字就是函数名
2.让函数内部的this指向这个对象(函数在创建的时候,this也已经创建了,但是此时this不知道指向谁。)
3.执行函数体内的代码,给 this 添加属性,就相当于给实例添加属性。
4.默认返回这个对象,所以构造函数不需要return
(如果有return:
1.return 基本数据类型,还是默认返回对象
2.return 一个复杂类型的数据例如数组,返回的就是该数组
例子如下:)

手写new
function _new(Fn,...arg){
  //1. 在内存种开辟一个空对象
  let obj  = {}
  //将新对象的对象原型指向构造函数的原型对象,否则,新对象的对象原型指向的是
obj._proto_ = Fn.prototype
  //2.将构造函数种的this指向这个对象,3并且执行构造函数,生产实例属性
  Fn.apply(obj,...arg)

  return obj
}
//手动添加一个基本数据类型的返回值,最终还是返回 this
function Person2() {
 this.age = 28;
 return 50;
}

var p2 = new Person2();
console.log(p2.age);   // 28

//手动添加一个复杂数据类型(对象)的返回值,最终返回该对象
function Person3() {
 this.height = '180';
 return ['a', 'b', 'c'];
}

var p3 = new Person3();
console.log(p3.height);  // undefined
console.log(p3.length);  // 3
console.log(p3[0]);      // 'a'

//定义构造函数
function Person(name, gender, hobby) {
    this.name = name;
    this.gender = gender;
    this.hobby = hobby;
}
//用new使用构造函数
var p1 = new Person('zs', '男', 'basketball');
var p2 = new Person('ls', '女', 'dancing');
var p3 = new Person('ww', '女', 'singing');
var p4 = new Person('zl', '男', 'football');
// ...


2. 原型链与原型对象

Es5与Es6

1.是什么

es5与js两者组成规范

2.区别

es5es6
变量声明varlet const var
没有箭头函数有箭头函数
反引号字符串拼接
解构赋值
… 展开运算符

Es6

1.模块化语法

暴露:export
接受:import

export

三种暴露
1.单个暴露:
暴露:变量,方法

	export let school = 'gc';

	export function teach() {
    	console.log("m1--我们可以教给你很多东西!");
	};

2.统一暴露:

	// 2. 统一暴露, m2.js
	let school = 'gc';

	function findJob() {
    	console.log("m2---我们可以帮助你找工作!!");
	};

	export {school, findJob};

3.默认暴露:

	export default {
    	school: 'ATLUCA',
    	change: function(){
        	console.log("m3---我们可以改变你!!");
    	}
	}
import

三种import 导入
1.通用导入
import * as 模块名 from ‘模块地址’

	// 1. 通用的导入方式
	// 引入 m1.js 模块内容
	import * as _m1 from "js/m1.js";
	_m1.teach();
	// 引入 m2.js 模块内容
	import * as _m2 from "js/m2.js";
	_m2.findJob();
	console.log(_m2.school);
	// 引入 m3.js
	import * as _m3 from "js/m3.js";
	console.log(_m3);
	_m3.default.change();

2.解构赋值形式
import { } from ‘模块地址’
注意点:1.{}中的变量名和导入的文件名字一样才能解构。
2. {}中的名字也可以改变 通过as

	// 2. 解构赋值形式
	// 引入 m1.js 模块内容
	import {school, teach} from "js/m1.js";
	console.log(school);
	// 引入 m2.js 模块内容
	// (1)如果导入的多个文件中,变量名字相同,即会产生命名冲突的问题,
	// (2)为了解决该问题, ES6为提供了重命名的方法。
	// (3)此处的school与m1.js的命名相同,所以此处的school改为gc
	import {school as gc, findJob} from "js/m2.js";
	console.log(findJob);
	// 引入 m3.js 模块内容
	import {default as _m3} from "js/m3.js";
	console.log(_m3);

3.简便形式,
注意:== 只针对于默认暴露==

import _m3 from "js/m3.js";

import 读取文件夹的顺序

按照规则,会去加载package.json,没有;则找index.js,没有;再找index.vue,找到了。

ES6模块化和commonjs 区别

dom+bom

dom和bom的关系

Dom

1.操作元素

在这里插入图片描述

2.操作元素内容

元素节点.innerText = ‘’;
元素节点.innerHTML= ‘’;
区别:innerHTML可识别标签,innerText 不可识别标签
在这里插入图片描述

3.操作元素属性(普通标签)

元素自带属性,元素自定义属性

元素自带属性:在这里插入图片描述
元素自定义属性:
在这里插入图片描述

4.操作表单属性(表单标签)

在这里插入图片描述
在这里插入图片描述

5.操作元素样式

JS 里面的样式采取驼峰命名法, 比如backgroundColor,不能出现-
两种操作

style
class: className,classList,
在这里插入图片描述

6.元素对象:滚动条,视口大小,

子盒子的大小只要超出了父盒子的内容大小,即碰到了父盒子的padding,就会出现滚动条。
在这里插入图片描述
content + padding +滚动条 +border+margin

clientheight = constent +padding
clientTop = 滚动条+border
offsetheight =content + padding+滚动条 +border
scrollHeight - scrollTop = clentHeight
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

document.write和elemnt.inerHTML和document.createdElement

Bom

bom是什么:BOM一个树状结构
在这里插入图片描述

window对象

window是整个BOM树食物链的顶端,因此每一个新打开的窗口,都被认为是一个window对象
所以有多个窗口就有多个window对象

在这里插入图片描述

定时器函数

注意:在创建定时器的时候,用变量申明的方式,为了在销毁的时候直接销毁变量就行。原因:定时器函数是引用类型数据,本体真正在堆空间中,销毁定时器的函数只能销毁栈空间的东西,用变量将定时器包裹住,这样销毁变量,同时能销毁定时器。如果不这样,定时器不能被真正销毁
在这里插入图片描述

window.getComputedStyle(DOM节点).getPropetyValue("padding-bottom")
//获取某个节点上,的csspadding-botomm的值。
//window.getComputedStyle(DOM节点) 获取某个节点上所有的属性,返回是一个对象,所以她的原型对象上有一个方法,getPropertyValue来获取对应属性的值
window.getComputedStyle(node).getPropetyValue("padding-bottom")
//创建延迟函数
setTimeout(function(){},毫秒数字)
//销毁
clearTimeout(延迟函数变量)

//创建延迟函数
setInterval(function(){},毫秒数字)
//销毁
clearInterval(延迟函数变量)
location对象

location对象是window对象的一个属性,提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。
注意:location对象不仅仅是window对象的一个属性,还是document对象的一个属性。所以
在这里插入图片描述

在这里插入图片描述

history对象

history 对象是 window 对象的属性,它保存着用户上网的记录,这个记录的时间戳是从窗口被打开的那一刻算起。
在这里插入图片描述

navigator对象

navigator对象,是BOM中识别客户端浏览器的一个window属性。

Bom与Dom区别

链接: DOM与BOM及其区别与用法

Bom=浏览器,
BOM 是 Browser Object Model,浏览器对象模型。BOM 是为了控制浏览器的行为而出现的接口。
对于JavaScript:为了能够让JavaScript能控制浏览器的行为,JavaScript就有了一套自己的BOM接口。

Dom=浏览器中的文档,目的:使JavaScript操作Html,JavaScript就有了一套自己的DOM编程接口。
DOM为JavaScript提供了一种访问和操作HTML元素的"方法"

在这里插入图片描述

dom,bo常见事件

dom 常见事件
dom 点击事件

鼠标位置信息:
在这里插入图片描述

正则表达式

1.test与match区别

在javascript中,用于检测一个字符串是否匹配某个模式用的比较多的就是test和match方法。
stringObj.match(正则表达式)
match是String的方法,参数是正则表达式,返回值是数组,没有找到时返回的是null。
正则表达式.test(string)
test是RegExp的方法,参数是字符串,返回值是boolean类型

前端实现下载

两种方法:
1.window.open
2. a标签+blod(二进制流实现文件下载)

1。window.open(‘url’)
是什么:window.open的url是文件在服务器上的地址,浏览器会直接下载文件
坏处:报错不能处理,下载出错就会出现乱码

2.blod+a标签(二进制流实现文件下载)
前置基础知识:
1.a标签能实现下载功能,需要以下两个属性
a.download =‘下载的文件名包括下载文件的格式’
a.href=‘文件的下载地址url’
2. blod:
是什么:Blob对象可以看做是一个用来存放二进制对象的容器
实现原理:
1) 使用ajax发起请求,指定接收类型为blob(responseType: ‘blob’)不指定的话默认后台返回的数据类型是JSON
2)读取请求返回的头部信息里的content-disposition,返回的文件名就在这里面(或者自定义文件名,可跳过此步骤)
3)使用URL.createObjectURL将请求的blob数据文档流转为可下载的url地址
4)使用js 模拟a标签下载
(5) URL.revokeObjectURL(ahref); // 释放URL 对象:为什么:在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,必须要释放掉,释放的方法有两种:手动释放,第二种将dom对象销毁即将a标签销毁会自动释放。

JS

VUE

vue2学习

vue2 data 为什么是函数

原因:为了防止data复用,相互影响。

当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据

1 render函数学习

是什么

代替template标签来创建html
这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.js 的 mount 函数,渲染成真实 DOM 节点,并挂载到根节点上。

为什么(好处)

VUE推荐在绝大多数情况下使用template来创建我们的HTML,但是有时候麻烦,用render更加方便快捷

怎么写
 render:h=>{
        return h(参数1,参数2,参数3)
      }

一共有三个参数
参数1:必填,类型:html标签(要用引号包含),vue组件,解析上述任何一种的一个 async 异步函数
参数1:html标签
在这里插入图片描述

参数1是vue组件
在这里插入图片描述

参数2:选填,类型:对象,包含模板相关属性的数据对象

在这里插入图片描述
domprops与props区别:
props是父组件向子组件传值
domprops:操作子组件的dom属性

参数3:

render坏处

2. 路由

2.1 路由 携带参数

query:刷新不丢失 ,与name和path连用
params:刷新丢失,只能与name连用

路由懒加载

1.什么是路由懒加载

(1)延迟加载,即在需要的时候进行加载,随用随载。
(2)把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件

2.路由懒加载好处(为什么)

(1)打包后js文件大
①路由中通常会定义很多不同的页面,这个页面这项目build打包后,一般情况下,会放在一个单独的js文件中,很多的页面都放在同一个js文件中,必然会造成这个页面非常大
(2)用户体验不好+白屏现象
①如果我们一次性的从服务器中请求下来这个页面,可能会花费一定时间,用户体验不好
②需要加载的内容过多,时间过长,会出啊先长时间的白屏,即使做了loading也是不利于用户体验

3.路由懒加载怎么写(三种方式)
(1)VUE异步组件
(2)ES6标准语法import
(3)Webpack的require,ensure

(1)VUE异步组件

(1)vue-router配置路由,使用vue的异步组件技术,可以实现懒加载,此时一个组件会生成一个js文件,多个组件生成多个js
(2)实现代码:
component: resolve => require([‘放入需要加载的路由地址’], resolve)
(3)使用样式:
在这里插入图片描述

(2)ES6标准语法import

let vue = () => import(/* 合并打包同名的变成1个js*/ ‘组件的地址’ )

在这里插入图片描述

3. vue 全局方法怎么弄

实现方式:
1.es6模块化 :在一个js中定义方法,通过es6模块化语法进行暴露获取,
2.mixin:缺点:(1)一个html多个mixins,多个mixins之间变量名相同和方法相同会互相覆盖,互相调用,且打包的时候会重复打包。
(2)组件 data 优先级高于 Mixin 混入的 data。
(3)先执行 Mixin 的钩子,再执行组件里的钩子
mixin的使用:
(1.)在mainjs中混入 vue.mixin()
(2)在app.vue中混入
(3)想在哪个文件用,在哪个文件混入
3.vue 原型对象上定义。 优点:简单,缺点:导致 单个vue实例过大不好
在main。js文件中会import vue,这个vue是一个构造函数,,app.vue是这个项目最大的vue实例对象。在这里插入图片描述

4.vue组件

template
script
style

5 动态样式

class 动态

总结:两种格式
1.数组形式 + 三元表达式/嵌套对象
2.对象形式 带true(不常用)

//数组格式
<div :class="['类名',{'类名':true},{'类名':false},三元表达式]"></div>
//对象格式

注意点:
1.v-bind:class
2.类名要提前在style上先写出来。 style
3.数组格式:中括号包含多个类,可以有三元表达式,嵌套对象形式的写法(区别直接使用对象)
对象格式 :大括号
在这里插入图片描述

在这里插入图片描述

style样式

总结:
1.对象的键有特殊符号,两种处理方式:用引号或者驼峰命名
2.对象的键和值,全都用引号,方便省心
3.style=[样式对象形式,样式对象形式]

在这里插入图片描述

<div :style="{字符串':”属性“,”字符串“:”属性值“}"></div>
computed:{
xxxx(){
return {
‘height’:'32px'}
}

这里是引用

6 vue指令

v-for 为什么key

就地复用策略:更快的渲dom。 dom的key就是标识,当key不变,dom不会更新。key变dom更新

template

vue.use(注册插件)

作用:注册插件:理解为新建一个或者新建多个vue实例模板,能随时用。

vue.use(参数1): 这个参数1只能有两种情况:
1.对象形式一定包含一个install函数
2.函数形式,本质上还是当成install函数处理

install()函数

7 vue2生命周期

父子vue生命周期

8 vue中文件夹的介绍

package.json

在这里插入图片描述

script配置

vue 全局

vue工作碰到的一些问题总结:

1.页面不渲染问题综合:

1.1 改变数组页面不渲染。(原理见vue2监听原理)

q:问题描述:数组与标签绑定。改变数组,页面不渲染。(暂时只有两种情况)

  1. 利用索引值直接改变一个值时,例如:this.arr[0] = 100。此时data中的arr[0]会变成100,但是不会渲染到页面上

solve: 通过索引值改变数组导致页面不渲染的解决方法:
通过this.$set(target,index,val)解决
在这里插入图片描述

  1. 当你修改数组的长度时,例如: this.arr.length = 100

数组的其他方法,例如push之类的还是会触发页面的更新。这些能被视图监听到
解决方法来源:链接: link

1.2改变对象,页面不渲染

两种情况:
1.属性的新增和删除
在这里插入图片描述
2. props传进来的对象属性已经被申明了,所以通过js改变,还是会监听得到,因该会变化,但是,页面上任然没有变化,
原因:1.有可能这个属性中途被复制过,已经有了两个对象,改变其中一个,两外一个没有改变。而页面渲染的是没有变化的。(也有可能是以为自己封装的组件将这个值给破坏了,)

solve:

链接: 监听对象

1.3 监听的数据格式: 【{},{}】数组包裹对象

vue2监听数组只能监听到第一层元素,第一层元素里面怎么变化是监听不到的。
解决方法:将修改的元素删除再插入回来,能触发监听。(vue3没有这个问题了)

2.看到得背景颜色和实际应用写的背景颜色有差异。

原因的可能性:
1.父级有背景颜色且当前子盒子背景颜色设置了透明度,导致父级背景颜色和子盒子背景颜色混合,呈现新的颜色。
solve:1.将父级的背景色改成白色
2.将子盒子背景颜色透明度删除。

3. vue项目怎么部署到服务器上。

1.首先得有一个服务器或者虚拟机,用来放置vue项目
2.自己的电脑上下载filezilla,filezilla可以将自己本地的文件传输到服务器上

4 /deep/

deep:

是什么:强行父组件改子组件,
原因:因为一般组件之间,style都用的scoped ,父组件改不了子组件,所以用/deep/强改

vue3 学习对比着vue2

vue2监听原理

原理:definePropety
在这里插入图片描述

1个对象 age
age对象经过构造函数Observer 生成新age,这个新的age在生成的过程中时候(即在构造函数Observer内部通过definePropety进行监听)
在这里插入图片描述

在这里插入图片描述

1.操作dom

el

vue2 this.$el $el指向当前组件template模板中的根标签
vue3 getCurrent().vnode.el 指向当前组件template模板中的根标签

ref

vue2 没有
vue3 const ref名字 = ref()ref名字.value

refs

vue2 this.$refs 获取当前组件内部所有的ref 返回结果:ref在vue实例上就返回vue实例对象(同时可以调用这个子组件暴露出来的方法,属性),ref在标签上返回的就是html节点dom。
vue3 getCurrent().proxy.refs.ref名称.value 获取当前组件内部所有的ref

vue 面试

node.js

node.js的模块化用法的commonjs的规范

暴露:module.export
导入:require(‘’)
1.暴露
两种写法(暴露变量,函数)
export(module.export 的简写)

var exports = module.exports;//等同于再每个模块头部先声明
exports.area = function (r) {
  return Math.PI * r * r;
};

exports.circumference = function (r) {
  return 2 * Math.PI * r;
};

注意:注意,不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。

exports = function(x) {console.log(x)};

module.export

const name = "swh"
const age = 18
 
function sum(num1, num2) {
  return num1 + num2
}
 
// 导出方案 module.exports
module.exports = {
  name,
  age,
  sum
}

2.导入
两种写法:
导入整个对象

const ajs  = require("./a.js")

导入并结构

const { name, age, sum } = require("./a.js")

webpack

webpack构建流程

git

git操作

1.项目创建到上传 (1.)git init 生成本地仓库
2.从githhub上获取代码:1.保证有git 2.git clone 地址 3.确定分支,切换分支 4.npm install

1.初始化生成git仓库

1.一个项目从未进行版本管理 git init
(会生成一个.git的隐匿目录,就是当前项目的git仓库)
2.从远端克隆一个仓库(克隆一整个仓库)
git clone https://gitee.com/xxxxxx/xx.git

2.本地代码管理

在这里插入图片描述

1.工作区–>暂存区
提交更新的文件:
单个文件 : git add 文件名
提交所有修改的文件:git add .
2. 暂存区–>本地仓库
git commit -m “提交信息描述”
3.本地仓库–>工作区(撤销文件的修改,撤销文件的commit, 实质

网络基础知识

web接口怎么防篡改防止重复

问题:一个接口用来充值。
不防篡改的后果

一个充值接口用给其他人的信息进行充值,
解决方法:前后端商定密钥,只有密钥匹配了才请求成功

不防重复:

什么是重复:同一个接口请求多次多次充值
解决方法:timestamp 时间戳,
原因:一个正常请求从发出到服务器60s以内,但是一般黑客抓包再放请请求会超过60s,所以,超过60s的请求无效
问题2:但是有可能60s之内发起请求
解决方法:1个随机字符(有效期也设置60s)+时间戳,60s之内的请求,一次正常的请求随机字符和第二次正常请求不一样,如果60s内黑客抓包并多次请求,随机字符是同一个也是无效。所以有时候我们短信验证码不能短时间验证多次就是应为这个。

http websoket tcp udp 各种协议

在这里插入图片描述

wesocket

WebSocket 协议本质上是一个==基于 TCP ==的协议,双工通信协议。

http 与https

http :超文本传输协议,基于 TCP/IP 协议
https: 安全套超文本传输协议。http协议+ssl协议。Ssl依靠证书验证服务器身份

区别:
https 安全,加密传输,http,明文传输
http响应速度比 HTTPS 快

tcp udp

在这里插入图片描述

输入url之后

在这里插入图片描述
在这里插入图片描述

面试

浏览器兼容问题

解决方法:
1.webpack 配置的时候配置css兼容问题
1.使用Normalize.css统一各个浏览器的默认样式
2.使用浏览器兼容检测工具:caniuse
3.使用css前缀:-webkit前缀来适配WebKit(Chrome、Safari)浏览器
3.一些针对性的:

设计模式

工厂模式

  //产品a
class productA {
  constructor(){
    this.name = 'productA'
  }
  action(){
    console.log('aaa')
  }
}
//产品b
class productB {
  constructor(){
    this.name = 'productB'
  }
  action(){
    console.log('aaa')
  }
}
// 工厂模式
class factory{
  constructor() {

  }
  createProduct(type){
    switch (type){
      case "A":
        return new productA()
        break;
      case "B":
        return new productB()
        break;
    }
  }
}
let factory =new factory()
const A =  factory.createProduct('A')

单例模式

let instance = null
//单例
class person {
  constructor() {
    this.name = '123'
  }
}

function singleTon(){
  if(!instance) instance = new Person()
  return instance
}
let aa =singleTon()
let bb =singleTon()

前端性能优化

链接: link

1.感知方面:
加loading或者骨架屏
2.html
(1)减少重绘重排
(2)减少http请求 :
webpack打包,cssjs合并;
图片:雪碧图,图片懒加载
3.js
防抖节流
减少操作DOM–>减少重排重绘
4.css
资源压缩:css-minimizer-webpack-plugin 可以压缩和去重 CSS 代码。
不要@import(@import在主css加载完了才加载,会导致页面加载速度变慢)
5.vue
keep-alive 组件
路由懒加载(按需加载的一种,使用import)
6.webpack
(1)在这里插入图片描述
(2)多入口打包:分割多个js文件code-split异步路由 ,然后预加载,再按需加载
(2) 预加载: script preload prefeatch
(3)按需加载js文件,import(js文件).then().catch() import返回promise
例如:点击按钮才会触发一个js文件的方法,可以放这个js文件按需加载。

7.资源加载优化
(1)web workers
一个独立的线程(独立的执行环境),这就意味着它可以完全和 UI 线程(主线程)并行的执行 js 代码,从而不会阻塞 UI,它和主线程是通过 onmessage 和 postMessage 接口进行通信的。用来处理纯数据,或者与浏览器 UI 无关的长时间运行脚本;
(2)DNS预解析
8浏览器缓存
9 服务器优化
静态资源使用CDN,在多个位置部署服务器

  1. 加载性能优化:
    • 1).核心减少请求次数。:同一域名下,同一GET请求的并发数是1,请求太多会放入队列,容易卡。
    • 2.)减少请求资源的大小:相同网络环境下,更小体积意味着传输速度更快
    • 3.)网络优化;
    • 4 )
      在这里插入图片描述
  2. 渲染性能优化
    • 1)资源加载优先级控制
    • 2)减少重排重绘
    • 3)页面缓存(keep-alive)
    • 4)Web Worker:用于那些处理纯数据,或者与浏览器 UI 无关的长时间运行脚本;

加载性能优化:4种

  • 1 减少请求次数:

    1. 图片的处理方式 :
      • 雪碧图
      • 图片懒加载
      • 字体图标(原因:图标字体小,渲染快,不要下载)
      • 图片的base64
    2. 利用缓存:
      • http缓存(资源):强制缓存协商缓存
      • DNS缓存(DNS查找时间)
      • 分包加载 (Bundle Spliting)
    3. 合并CSS和JS文件
      • 将CSS和JavaScript文件合并为单独的文件。合并CSS和JavaScript文件是减少HTTP请求数量和提高网站加载速度的有效方法;
  • 2.减少资源大小

    1. 资源压缩体积
      • html ,css,js 压缩 用gzip压缩
        在这里插入图片描述

      • 图片资源压缩
        在这里插入图片描述

  1. Tree Shaking减少资源体积
    • Tree Shaking: 无用导出将在生产环境进行删除,到达减少资源体积的效果;
  • 3.网络优化

在这里插入图片描述

渲染性能优化方式:3个

  • 1)资源加载优先级控制
    webpack配置http请求优先级(preload/prefetch)
    css放head尾部,script放body尾部,同时defer和async
    在这里插入图片描述

  • 2)减少重排重绘

    • 减少页面DOM操作;
    • 对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。例如:隐藏元素(display:none)、文档碎片(DocumentFragement)等(虚拟dom);
    • 用 JavaScript 修改样式时,最好不要直接修改单个样式属性,而是替换 class 来改变样式;
    • 合理使用防抖和节流;
  • 3)利用缓存

    • 页面缓存(keep-alive),接口缓存(减少数据更新导致的页面刷新)
  • 4)Web Worker

    • 用于那些处理纯数据,或者与浏览器 UI 无关的长时间运行脚本;

html

bfc

bfc是什么

块级格式上下文。
内部布局规则:垂直方向一个接一个
每一个BFC区域只包括其子元素不包括其子元素的子元素。

bfc用处

在浏览器页面中创立了一个独立渲染的区域,bfc内部的元素无论怎么样都不会影响到bfc外面的元素。

bfc如何产生

脱标+display+overflow

    1.浮动的元素,除了float:none
    2.定位:absolute和fixed  
    3.diplay:inline-block,table(行内块元素),flex(弹性布局)
    4.overflow:不是visible,
                       hidden(推荐)
用处1:清除浮动带来的影响

问题:父盒子没有设置宽高,子盒子浮动,父盒子不会被撑开。
bfc内部的盒子就算是浮动的也参加计算
所以:清除浮动,父元素设置为bfc,子盒子就算浮动也要进入计算,所以父盒子还是被子盒子撑高了。

用处2:解决margin塌陷

1.外边距塌陷:将两个盒子分别放在两个bfc中。即将两个盒子通过两个bfc盒子进行隔离。
2.包含塌陷:将父盒子变成bfc盒子。子盒子就不会和父盒子产生塌陷。父盒子内的子元素不会影响到父盒子的外面,以父盒子的border为界限。子元素不会影响到父盒子border以外的东西。

css引入

css引入三种:内嵌,外联,行内式

1.行内式

标签内部 style =“”

2.内嵌:

head标签内部style标签
在这里插入图片描述

3.外联:

外联有两种方法link与@import

3.1 link head标签中link标签

在这里插入图片描述

3.2 @import head标签中style标签@import

在这里插入图片描述
在这里插入图片描述

link和@import区别:5点
1、从属关系:link是html的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等;而@import是css的语法,只有导入样式表的作用。
2、加载顺序:页面被加载时,link会和html同时被加载而;@import引入的 CSS 将在页面加载完毕后被加载。(@import是再dom树渲染完毕之后,才加载的)
3、兼容性:@import是 CSS2.1 才有的语法,所以只能在 IE5以上 才能识别;而link是 HTML 标签,所以不存在兼容性问题。
4、DOM:javascript只能控制dom去改变link标签引入的样式,而@import的样式不是dom可以控制的。(@import不能通过js'代码控制,link引入的标签是可以的。)
5、link方式的样式权重高于@import的权重。
link和@import使用场景区别

@import是依赖css的,存在一定的兼容问题,并且根据浏览器渲染机制来说,他在dom树渲染完成后才会渲染,并且不能被js动态修改。相比之下link兼容性较好,且dom元素的样式可以被js动态修改,又因为link的权重高于@import,
所以 @import适用于引入公共基础样式或第三方样式,link适用于自己写的且需要动态修改的样式

简述src和href的区别

相同点:都是引用外部资源
不同点:

hrefsrc
link,a标签使用script,imag,video,audio等标签使用
将当前元素和外部资源建立联系,当浏览器解析到href时,解析不会停止src用外部资源替换当前元素,当浏览器解析到src时,会暂停浏览器的解析,去下载外部资源。所以再用script引入js文档的时候,要写在最后,目的是最后去去加载js文档

行内元素,行内块,块元素

1.行内元素:
2.行内块元素:
3.块元素:

行内元素行内块元素块元素
一行多个一行多个独占一行
不可设置宽高,宽高就是内容大小,行内元素的宽高是被内容撑开,设置宽度,高度,以及行高,和text-align都是无效的可设置宽高可设置宽高
水平方向上的padding和margin可以设置,垂直方向上的无效水平方向上的padding和margin可以设置,垂直方向上的无效margin,padding都能设置
行内元素中只能放行内元素标签或者纯文本==(a标签除外,a里面不可以放自己)==块级标签内部能放块,行内块,行内元素
标签a,span,伪元素,img(可以当行内块使用)input,textarea,button,selectdiv,p,h,ul li,ol li,dldtdd

css

1.水平垂直居中

1.text-align:center+line-height:height

2个元素,父 块元素,子元素:行内块,行内元素, 宽可以不知道,高一定要知道
text-align:center: 写在父级。会继承,生效对象:行内块,行内元素,文本
line-height:只会在行内元素,行内块元素或者文字上生效,就算写在块元素上,这个块本身不受影响,但是块中只要有行内元素,行内块元素和文字,就会继承到他们身上。所以效果作用的对象是行内元素,行内块元素和文字

2.使用绝对定位 + transform

2个块元素之间水平垂直居中. 。不知道宽高
这种方式比较常用,父子元素都不确定宽高的情况也适用。
父:块元素1个
子:块元素1个

3.margin:auto

2个块元素之间水平垂直居中,
父:块元素1个
子:块元素1个

4. flex布局

父亲一个,子多个或1个
链接: flex布局在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

5.vertical-align

多个行内元素或者行内块(置换元素即表单标签)
vertical-align 属性只能用于== 行内元素 和 置换元素==(例如 图像和表单输入框) ,此属性不继承

2 样式的消失与出现

display:none/display:block :不占位 ,浏览器重绘重排消耗性能
opacity:0/1 :存在看不见 浏览器重绘不会重排
visibility:hidden;/

css 提高新能优化

见前端性能优化

js

1.精度缺失问题:

1.为什么
计算机对于数据都是转换为二进制存储的,但是对于某些浮点数计算机无法将其精确表达为二进制
2.解决办法 2种
1.先放大在缩小
将需要运算的小数扩大10倍、100倍、。。。将小数扩大到整数,然后进行运行,最后再缩小扩大的倍数。例:

var num1 = 0.1
var num2 = 0.2
var num3 = (num1 * 10 + num2 * 10) / 10
console.log(num3) // 0.3
	2.通过js中Number的内置方法toFixed,强制保留小数点后位数。例
var num1 = 0.1
var num2 = 0.2
var num3 = num1 + num2
console.log(num3.toFixed(3)) // 0.300 - 强制保留小数点后3位

2. 解决回调地狱

链接: 解决回调地狱
js中实现异步的方式:1.回调函数
1。什么是回调地狱:
回调函数在满足某个条件才触发,依次执行多个回调函数,就会有多个回调函数嵌套。难以维护和阅读。
2.解决回调地狱:promise 将异步任务变成同步任务,就不用用回调函数了,用promise代替回调函数。变成链式编程,这样的的话容易读懂
es7又怎加async和await语法糖(目的是让异步看着像同步,容易阅读)
promise().then().then(()=>{}).then…catch(()=>{在这里抓取错误,只要前面任意一个then执行不成功报错,用catch捕获})。finally(()=>{在所有回调都结束了,在调用finally在这里可以做清除的工作。})

3.window.location.href,window.open,打开新页面区别

window.location.href是刷新当前页面,也就是更新浏览器地址栏。

window.open是新打开一个标签页

是一个连接地址,href="/"是指连接到的地址,没写target属性则认为是在当前页打开这个连接,效果和window.location.href一样。如果写了target 就和window。open一样。

4. 函数同名和变量同名会怎么样

1.函数外部变量和函数重名

避免变量名和函数名同名,否则会发生相互覆盖的问题
定义变量时只使用var定义变量,不分配变量初始值,此时函数的优先级更高,函数会覆盖变量;
定以变量时为变量指定了初始值,此时变量的优先级更高,变量会覆盖函数.

2.函数内部变量和函数重名

函数名称与内部变量名称冲突,就会永远优先执行函数本身。

3.两个函数重名

后一个函数覆盖前一个函数,只要名字一样不问参数

解决:多人开发怎么解决函数命名重复

1.将函数包装在对象的属性中,这样就可以避免函数名冲突的问题。
在这里插入图片描述
2.闭包函数
3.模块化开发的方式来组织代码
将公用的方法写在同一个文件里面,通过commonjs或者es6 的语法共同使用。
4.使用唯一的前缀(将同名函数区别)

5.this 指向问题*****

1

1.函数定义在window里面: 直接调用函数,this指向window
2.函数在对象里面:调用函数,this就是这个对象(谁调用函数,this就指向谁)
3.构造函数:构造函数的this指向new出来的实例对象
4.箭头函数: 箭头函数没有this,箭头函数的this取决于包裹他第一个的外层this是什么,就是什么。并且call,bind这些不能改变箭头函数的this指向,因为箭头函数没有this
this的指向优先级:new>bind,call>obj.fun()>fun()

6 == 与 === 区别

== 会转化比较者的数据类型。基本数据类型

vue

vue传参

10个
父子传参 props $emit
ref
p a r e n t , parent, parent,children
祖孙:inject provide
inheritattrs $attrs $ listeners
在这里插入图片描述

vuex
pinia
事件总线
localstorage sessuonstorage
slot插槽

vue2 vue3响应式

vue2响应式:通过Object.definepropert() 对属性进行读取和修改,就是数据劫持。在数据更新时发布消息给订阅者,触发相应监听回调
vue3响应式:通过proxy+reflect 将通过对象生成proxy代理对象,对代理对象进行操作,再通过reflect反射到原对象。

vue生命周期

vue2
在这里插入图片描述
vue3
setup onbeforeMounted onMounted onbeforeUpadated onUpadatd onbeforeUnMounted onUnmounted

vue 引入图片的时候遇到的问题。

1.静态资源和动态资源

静态资源:在vue项目本地 vue2: static assert vue3:public assert ,static(vue2) 等于public(vue3)
动态资源:通过ajax请求回来的。

  1. vue中引入图片 静态引入和动态引入

静态引入:
文件在static中 ,直接写 src= “static文件夹下的名称”
在这里插入图片描述
文件在assert中,使用相对路径,绝对路径都可以
绝对路径
在这里插入图片描述
相对路径
在这里插入图片描述
动态引入:
链接: 动态引入
需要引入require
原因:浏览器只会运行,html,css,js等代码,vue项目在npm run 之后会经过编译,再在浏览器中运行。在编译的时候,会将动态地址编译成一个静态的字符串地址,原封不动的保留。但是图片所在的文件会根据webpack打包进行配置,图片小的直接转成base64嵌入,图片大的会生成新的目录文件,这样的话导致静态的字符串地址和文件打包后形成的地址不同,导致图片炸裂
how to solve :impot 和solve 都可以
1.require
require将图片当成一个模块,进行打包
通过require方法拿到的文件地址,是资源文件编译过后的文件地址(dist下生成的文件或base64文件),因此可以找对应的文件,从而成功引入资源。

node

git

1.初始化本地仓库:git init

在这里插入图片描述

2.克隆远程仓库 git clone +地址
在这里插入图片描述
3.查看当前仓库状态 git status
4 查看日志 git log q退出

5.提交到暂存区
提交所有文件:git add .
在这里插入图片描述
提交单个文件:git add 文件名

6.提交本地仓库
git commit -m ‘xxxxx’
修改上一次commit提交信息
git commit --amend 修改完毕知 保存退出 (:wq ) 不保存退出 qa+回车键
7.本地仓库连接远程仓库
git remote add origin https://gitee.com/hannibalmicheal/practisegitorder.git
8 提交到本地仓库
git push origin 远程仓库名

8 回滚本地代码仓
git reset – soft(本地仓库移动到最后一次之前的一次,即删除本地仓库的最后一次,但是工作区,暂存区的都没有发生变化) --mixed (本地仓库head,暂存区 最后一次都删除,工作区所有代码都不变)-- hard(本地仓库的head,暂存,工作区全部变成之前的) id/head~次数/head^上以一个版本
撤回上一次commit或者指定或者前好几次 :git reset id/head~几次/head^
撤回暂存区:git reset 文件路径 (原理:head指向最后一个commit,mixed模式 暂存区丢失最后一个commit后面的文件修改,工作区保持不变)
9 删除工作区文件 :git rm 本地仓库和暂存区不受影响
10撤销工作区文件的修改:git checkout 文件地址 原理:在这里插入图片描述
所以暂存区有用暂存区的,没有就用commit的
11 切换分支 git checkout
12 创建本地+切换到新分支 git checkout -b dev
在这里插入图片描述
13 删除本地分支
在这里插入图片描述
14 修改本地分支名 :在这里插入图片描述

15提交本地分支到远程分支:1.第一次git push -u origin 远程分支名 2.不是第一次 git push
16 删除远程分支
17 更新代码:1.跟新本分支代码 git pull2. 更新所有分支代码git pull -all

uniapp

微信小程序

TS

1.接口 类 泛型 关系
接口 约束变量 函数 数组
接口约束类
接口约束泛型

泛型在接口,函数,类定义的时候可以使用
接口继承接口
接口继承类

2 类型断言
3.类型推论
4 联合类型
5 交叉类型 &

webpack vue-cli vite

1、webpack的作用是什么,谈谈你对它的理解?

现在的前端网页功能丰富,特别是SPA(single page web application 单页应用)技术流行后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决Scss,Less……新增样式的扩展写法的编译工作。
所以现代化的前端已经完全依赖于webpack的辅助了。
现在最流行的三个前端框架,可以说和webpack已经紧密相连,框架官方都推出了和自身框架依赖的webpack构建工具。
react.js+WebPack
vue.js+WebPack
AngluarJS+WebPack
2、webpack的工作原理?
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。在3.0出现后,Webpack还肩负起了优化项目的责任。
3、webpack打包原理
把一切都视为模块:不管是 css、JS、Image 还是 html 都可以互相引用,通过定义 entry.js,对所有依赖的文件进行跟踪,将各个模块通过 loader 和 plugins 处理,然后打包在一起。
按需加载:打包过程中 Webpack 通过 Code Splitting 功能将文件分为多个 chunks,还可以将重复的部分单独提取出来作为 commonChunk,从而实现按需加载。把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载
4、webpack的核心概念
Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js
output :出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./dist
Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。
5、Webpack的基本功能有哪些?
代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
文件优化:压缩 JavaScript、CSS、html 代码,压缩合并图片等
代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
6、gulp/grunt 与 webpack的区别是什么?
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。grunt和gulp是基于任务和流(Task、Stream)的。
类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。webpack是基于入口的。
webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
7、webpack是解决什么问题而生的?
如果像以前开发时一个html文件可能会引用十几个js文件,而且顺序还不能乱,因为它们存在依赖关系,同时对于ES6+等新的语法,less, sass等CSS预处理都不能很好的解决……,此时就需要一个处理这些问题的工具。

css 压缩:插件
css编译:
在这里插入图片描述
css兼容:postcss-loader
css 单独打包 :利用插件
css 压缩:插件

js

js压缩:默认开启
js编译:webpack自动编译js
js兼容 :babel
js ;HMR

html

html 压缩默认开启

webpack打包速度性能优化

1 hmr 模块热替换
2. 多入口打包
3. exclude include属性
4.

在这里插入图片描述

##前端安全
###xss跨线脚本攻击

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值