当前位置:   article > 正文

前端笔记1_chrome 跟mozillia和netscape

chrome 跟mozillia和netscape

HTML

概念

超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。(是标记语言,不是编程语言)

内核

浏览器内核的理解
主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。

JS引擎则:解析和执行javascript来实现网页的动态效果。

最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
常见的浏览器内核
Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称MSHTML]
Gecko内核:Netscape6及以上版本,FireFox,MozillaSuite/SeaMonkey等
Presto内核:Opera7及以上。      [Opera内核原为:Presto,现为:Blink;]
Webkit内核:Safari,Chrome等。   [ Chrome的:Blink(WebKit的分支)]
  • 1
  • 2
  • 3
  • 4

详细文章:浏览器内核的解析和对比

私有前缀
前缀浏览器例 border-radius:10px;
-webkit-chrome和safari-webkit-border-radius:10px; 兼容chrome和Safari
-moz-Firefox-moz-border-radius:10px; 兼容Firefox
-ms-IE-ms-border-radius:10px; 兼容IE
-o-Opera-o-border-radius:10px; 兼容opera

web标准:w3c万维网联盟

标准说明备注
结构结构用于对网页元素进行整理和分类,主要是HTML。结构示例
表现表现用于设置网页元素的版式、颜色、大小等外观样式,主要指的是CSScss示例
行为行为是指网页模型的定义及交互的编写,主要是 Javascript在这里插入图片描述

理想状态我们的源码: .HTML .css .js

html文件结构

img

  • 声明为 HTML5 文档,doctype 声明是不区分大小写的

  • 元素是 HTML 页面的根元素

  • 元素包含了文档的元(meta)数据,如 定义网页编码格式utf-8

  • 元素描述了文档的标题

  • 元素包含了可见的页面内容

  • 元素定义一个大标题

  • 元素定义一个段落

  • lang可以启用网页的翻译功能

    lang:en 、zh-CN、 fr

通用声明
HTML5
HTML 4.01
XHTML 1.0

查看完整网页声明类型 DOCTYPE 参考手册

标签

HTML 标签参考手册 - 功能排序 (w3school.com.cn)

基础
标签描述
<!DOCTYPE>定义文档类型。
定义 HTML 文档。
定义关于文档的信息。
定义文档的标题。
定义文档的主体。

to

定义 HTML 标题。

定义段落。

定义简单的折行。

定义水平线。
<!–…—>定义注释。
格式化
标签描述
定义只取首字母的缩写。HTML5 中不支持。请使用 代替。
定义缩写。
定义文档作者或拥有者的联系信息。
定义粗体文本。
定义文本的文本方向,使其脱离其周围文本的方向设置。
定义文字方向。
定义大号文本。HTML5 中不支持。请使用 CSS 代替。
定义长的引用。
定义大号文本。HTML5 中不支持。请使用 CSS 代替。
定义引用(citation)。
定义计算机代码文本。
定义被删除文本。
定义定义项目。
定义强调文本。
定义大号文本。HTML5 中不支持。请使用 CSS 代替。
定义斜体文本。
定义被插入文本。
定义键盘文本。
定义有记号的文本。
定义预定义范围内的度量。
定义预格式文本。
定义任何类型的任务的进度。
定义短的引用。
定义若浏览器不支持 ruby 元素显示的内容。
定义 ruby 注释的解释。
定义 ruby 注释。
定义加删除线的文本。
定义计算机代码样本。
定义小号文本。
定义加删除线文本。HTML5 中不支持。请使用 代替。
定义语气更为强烈的强调文本。
定义上标文本。
定义下标文本。
定义用作容纳页面加载时隐藏内容的容器。
定义日期/时间。
定义打字机文本。HTML5 中不支持。请使用 CSS 代替。
定义下划线文本。
定义文本的变量部分。
定义可能的换行符。
表单和输入
标签描述
定义供用户输入的 HTML 表单。
定义输入控件。同一组radio、checkbox要有相同的name属性
定义多行的文本输入控件。
定义按钮。
定义选择列表(下拉列表)。
定义选择列表中相关选项的组合。
定义选择列表中的选项。
定义 input 元素的标注。“for” 属性可把 label 绑定到另外一个元素。请把 “for” 属性的值设置为相关元素的 id 属性的值
定义围绕表单中元素的边框。
定义 fieldset 元素的标题。
定义与文档相关的可搜索索引。HTML5 中不支持。
定义下拉列表。
定义生成密钥。
定义输出的一些类型。
框架
标签描述
定义框架集的窗口或框架。HTML5 中不支持。
定义框架集。HTML5 中不支持。
定义针对不支持框架的用户的替代内容。HTML5 中不支持。
定义内联框架。
图像
标签描述
定义图像。
定义图像映射。
定义图像地图内部的区域。
定义图形。
定义 figure 元素的标题。
定义媒介内容的分组,以及它们的标题。
定义 SVG 图形的容器。
音频/视频
标签描述
定义声音内容。
定义媒介源。
定义用在媒体播放器中的文本轨道。
定义视频。
链接
标签描述
定义锚。锚点链接(页面内跳转):使用id,如
定义文档与外部资源的关系。
定义导航链接。
列表
标签描述
    定义无序列表。
      定义有序列表。
      定义列表的项目。
      定义大号文本。HTML5 中不支持。请使用 CSS 代替。
      定义定义列表。
      定义定义列表中的项目。
      定义定义列表中项目的描述。
      定义命令的菜单/列表。
      定义用户可以从弹出菜单调用的命令/菜单项目。
      定义命令按钮。
      表格
      标签描述
      定义表格
      定义表格标题。
      定义表格中的表头单元格。
      定义表格中的行。
      定义表格中的单元。
      定义表格中的表头内容。
      定义表格中的主体内容。
      定义表格中的表注内容(脚注)。
      定义表格中一个或多个列的属性值。
      定义表格中供格式化的列组。
      样式和语义
      标签描述
      元信息
      标签描述
      定义关于文档的信息。
      定义关于 HTML 文档的元信息。
      定义页面中所有链接的默认地址或默认目标。
      定义页面中文本的默认字体、颜色或尺寸。HTML5 中不支持。请使用 CSS 代替。
      编程
      标签描述

      字符

      如空格等等

      HTML ISO-8859-1 参考手册 | 菜鸟教程 (runoob.com)

      HTML 符号实体参考手册 | 菜鸟教程 (runoob.com)

      字符实体编号实体名称描述
      >&gt
      <&lt
      &#160&nbsp非间断空格(non-breaking space)

      HTML5

      <!doctype> 声明必须位于 HTML5 文档中的第一行,使用非常简单:

      <!DOCTYPE html>
      
      • 1
      新特性

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

      • 用于绘画的 canvas 元素
      • 用于媒介回放的 video 和 audio 元素
      • 对本地离线存储的更好的支持
      • 新的特殊内容元素,比如 article、footer、header、nav、section
      • 新的表单控件,比如 calendar、date、time、email、url、search
      • 已移除的元素,以下的 HTML 4.01 元素在HTML5中已经被删除:
      - <acronym>
      - <applet>
      - <basefont>
      - <big>
      - <center>
      - <dir>
      - <font>
      - <frame>
      - <frameset>
      - <noframes>
      - <strike>
      - <tt>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      新元素
      标签描述
      标签定义图形,比如图表和其他图像。该标签基于 JavaScript 的绘图 API

      新多媒体元素
      标签描述
      定义音频内容
      定义视频(video 或者 movie)
      定义多媒体资源 和
      定义嵌入的内容,比如插件。
      为诸如 和 元素之类的媒介规定外部文本轨道。

      新表单元素
      标签描述
      定义选项列表。请与 input 元素配合使用该元素,来定义 input 可能的值。
      规定用于表单的密钥对生成器字段。
      定义不同类型的输出,比如脚本的输出。

      新的语义和结构元素

      HTML5提供了新的元素来创建更好的页面结构:

      标签描述
      定义页面独立的内容区域。
      定义页面的侧边栏内容。
      允许您设置一段文本,使其脱离其父元素的文本方向设置。
      定义命令按钮,比如单选按钮、复选框或按钮
      用于描述文档或文档某个部分的细节
      定义对话框,比如提示框
      标签包含 details 元素的标题
      规定独立的流内容(图像、图表、照片、代码等等)。
      定义
      元素的标题
      定义 section 或 document 的页脚。
      定义了文档的头部区域
      定义带有记号的文本。
      定义度量衡。仅用于已知最大和最小值的度量。
      定义导航链接的部分。
      定义任何类型的任务的进度。
      定义 ruby 注释(中文注音或字符)。
      定义字符(中文注音或字符)的解释或发音。
      在 ruby 注释中使用,定义不支持 ruby 元素的浏览器所显示的内容。
      定义文档中的节(section、区段)。
      定义日期或时间。
      规定在文本中的何处适合添加换行符。

      已移除的元素

      以下的 HTML 4.01 元素在HTML5中已经被删除:

      css

      选择器

      基础选择器
      • 标签选择器
      • 类选择器 .
      • id选择器 #
      • 通配符选择器 *
      复合选择器
      后代选择器

      选取某元素的后代元素。div p { background-color:yellow; }

      子选择器

      与后代选择器相比,子元素选择器(Child selectors)只能选择作为某元素直接/一级子元素的元素。div>p { background-color:yellow; }

      并集选择器

      div,p { background-color:yellow; }

      CSS伪类/伪元素

      这四个按照顺序:link :visited :hover :active声明

      n可以为数字;n也可以为关键字:even-偶数,odd-奇数;n也可以为公式如n,2n,2n+1,n从0开始

      选择器示例示例说明
      :checkedinput:checked选择所有选中的表单元素
      :disabledinput:disabled选择所有禁用的表单元素
      :emptyp:empty选择所有没有子元素的p元素
      :enabledinput:enabled选择所有启用的表单元素
      :first-of-typep:first-of-type选择的每个 p 元素是其父元素的第一个 p 元素
      :in-rangeinput:in-range选择元素指定范围内的值
      :invalidinput:invalid选择所有无效的元素
      :last-childp:last-child选择所有p元素的最后一个子元素
      :last-of-typep:last-of-type选择每个p元素是其母元素的最后一个p元素
      :not(selector):not§选择所有p以外的元素
      :nth-child(n)p:nth-child(2)选择所有 p 元素的父元素的第二个子元素。和:nth-of-type(n)的区别是:nth-child先选择第n个孩子。再看是不是p标签,nth-of-type是选择p标签的第二个
      :nth-last-child(n)p:nth-last-child(2)选择所有p元素倒数的第二个子元素
      :nth-last-of-type(n)p:nth-last-of-type(2)选择所有p元素倒数的第二个为p的子元素
      :nth-of-type(n)p:nth-of-type(2)选择所有p元素第二个为p的子元素
      :only-of-typep:only-of-type选择所有仅有一个子元素为p的元素
      :only-childp:only-child选择所有仅有一个子元素的p元素
      :optionalinput:optional选择没有"required"的元素属性
      :out-of-rangeinput:out-of-range选择指定范围以外的值的元素属性
      :read-onlyinput:read-only选择只读属性的元素属性
      :read-writeinput:read-write选择没有只读属性的元素属性
      :requiredinput:required选择有"required"属性指定的元素属性
      :rootroot选择文档的根元素
      :target#news:target选择当前活动#news元素(点击URL包含锚的名字)
      :validinput:valid选择所有有效值的属性
      :linka:link选择所有未访问链接
      :visiteda:visited选择所有访问过的链接
      :activea:active选择正在活动链接
      :hovera:hover把鼠标放在链接上的状态
      :focusinput:focus选择元素输入后具有焦点
      :first-letterp:first-letter选择每个

      元素的第一个字母

      :first-linep:first-line选择每个

      元素的第一行

      :first-childp:first-child选择器匹配属于任意元素的第一个子元素的

      元素

      :beforep:before在每个

      元素之前插入内容,::before也对

      :afterp:after在每个

      元素之后插入内容,::after也对

      :lang(language)p:lang(it)

      元素的lang属性选择一个开始值

      .img:hover:before{

      }

      属性选择器

      CSS 属性选择器 | 菜鸟教程 (runoob.com)

      下面的例子是把包含属性value的所有元素变为蓝色:

      [value] { color:blue; }

      下面的例子是把包含属性value的所有input元素变为蓝色:

      input[value] { color:blue; }

      属性和值选择器

      下面的实例改变了属性title='runoob’元素的边框样式:

      [title=runoob] { border:5px solid green; }

      属性和值的选择器 - 多值

      下面是包含指定值的title属性的元素样式的例子,使用(~)分隔属性和值:

      [title~=hello] { color:blue; }
      <h1 title="hello world">Hello world</h1>
      
      • 1
      • 2

      下面是包含指定值的lang属性的元素样式的例子,使用(|)分隔属性和值:

      [lang|=en] { color:blue; }

      尺寸

      px:像素单位

      rpx:小程序端常用,1px=2rpx,1rpx=1物理像素

      em:当前元素(font-size)1个文字的大小

      引入方式

      内部样式表

      行内样式表style=""

      外部样式表

      元素显示模式

      display属性设置

      块级元素block

      div ul ol li dl dt dd h1 h2 h3 h4…p

      p和h标签内部不能放其他块级元素

      自己独占一行(设置宽高后也是)

      行内元素(内联元素)inline

      a b span img input select strong

      行内元素的宽高直接设置时无效

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

      里面不能放,特殊情况里面可以放块级元素

      行内块inline-block

      和其他行内或行内块级元素元素放置在同一行上; 元素的高度、宽度、行高以及顶 和底边距都可设置。

      line-height和height

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6dvfmWF-1646544115479)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220127215745787.png)]

      颜色

      rgb,rgba,#FFFFFF

      三大特性

      层叠性

      层叠性是多种CSS样式的叠加,是浏览器处理样式冲突的方式。在HTML中对于同一个元素可以有多个CSS样式存在,当有相同权重的样式存在时,会根据这些样式出现的先后顺序来决定,处于最后面的CSS样式将会覆盖前面的CSS样式。

      举例,这就是样式冲突。

      div{
          color:red;
      }
      div{
          color:blue;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 原则
        通常出现样式冲突,会按CSS书写的顺序,以最后的样式为准。
      1. 样式不冲突,不会层叠。
      2. 样式冲突,遵循就近原则。 长江后浪推前浪,后面样式盖前面。
      继承性
      • 说明
        简单的理解为—“子承父业“,是指子标签会继承父标签的==某些==样式,如文本颜色和字号。想要设置一个可继承的属性,只需将它应用于父元素即可。
      • 举例
      <style>
          div{color:pink;font-size:20px;}
      </style>
      <div>
          <span>
              我是什么颜色的?
          </span>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 注意
      1. 合理使用继承可以简化代码,降低CSS样式的复杂性。对于字体、字号、颜色、行距等**文本类属性**具有继承性,都可以在body中统一设置,然后影响文档中所有文本。
      2. 但是,并不是所有的CSS属性都可以继承,如边框、外边距、内边距、背景、定位、元素高度等**与块级元素相关的**属性都不具有继承性
      优先级

      在复杂CSS样式表,往往并不是相同样式不同值的堆叠这么简单,经常出现两个或多个不同样式规则应用在同一元素上,这时到底采用哪个样式呢?这就是典型的CSS优先级问题。

      处理优先级问题,就是考虑样式权重的高低。这里先给大家介绍一些特殊的情况:

      1. **继承样式的权重为0。**也就是说,在嵌套结构中,无论父元素样式权重多大,子元素继承时,应用在子元素上的权重都为0,即子元素定义的样式会覆盖所有继承来的样式。
      2. **行内样式优先。**应用style属性的元素,其行内样式的权重非常高,可以理解为远大于100。总之,他拥有比上面提高的选择器都大的优先级。
      3. 权重相同时,CSS遵循就近原则。也就是说靠近元素的样式具有最大的优先级,或者说排在最后的样式优先级最大。
      4. CSS定义了一个!important命令,该命令被赋予最大的优先级。也就是说不管权重如何以及样式位置的远近,!important都具有最大优先级。
      CSS特殊性
      • 说明
        或称非凡性,是需要用一套计算公式来去计算CSS的权重。CSS的权重是一个衡量CSS值优先级的一个标准,规则如下:
        用一个四位的数字串(CSS2是三位)来表示,更像四个级别,值从左到右,左面的最大,一级大于一级,数位之间没有进制,级别之间不可超越。

      img

      • 注意
      1. 继承的权重为 0。
      2. 数值之间没有进制计算,比如: 0,0,0,5 + 0,0,0,5 =0,0,0,10 而不是 0,0, 1, 0, 所以不会存在10个div等于一个类选择器的状况。
      3. 权重是用来计算优先级的,层叠是来表现优先级的。
      • 总结优先级
        !important>行内样式> ID 选择器>类(伪元素、伪类、属性)选择器>元素选择器>通用选择器
      1. 使用了 !important声明的规则。
      2. 内嵌在 HTML 元素的 style属性里面的声明。
      3. 使用了 ID 选择器的规则。
      4. 使用了类选择器、属性选择器、伪元素和伪类选择器的规则。
      5. 使用了元素选择器的规则。
      6. 使用了通配符的规则。
      7. 同一类选择器则遵循就近原则。

      盒子模型

      CSS box-model

      • Margin(外边距) - 清除边框外的区域,外边距是透明的。

      行内元素可以设置左右margin

      margin-left:auto 可以使元素居中

      • Border(边框) - 围绕在内边距和内容外的边框。
      • Padding(内边距) - 清除内容周围的区域,内边距是透明的。

      行内元素可以设置padding,但无法撑开盒子

      • Content(内容) - 盒子的内容,显示文本和图像。
      元素的宽度和高度

      Remark重要: 当您指定一个 CSS 元素的宽度和高度属性时,你只是设置内容区域的宽度和高度。要知道,完整大小的元素,你还必须添加内边距,边框和外边距。

      总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距

      元素的总高度最终计算公式是这样的:

      总元素的高度=高度+顶部填充+底部填充+上边框+下边框+上边距+下边距

      box-sizing 属性
      说明
      content-box默认值。如果你设置一个元素的宽为 100px,那么这个元素的内容区会有 100px 宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。
      border-box告诉浏览器:你想要设置的边框和内边距的值是包含在 width 内的。也就是说,如果你将一个元素的 width 设为 100px,那么这 100px 会包含它的 border 和 padding,内容区的实际宽度是 width 减 去(border + padding) 的值。大多数情况下,这使得我们更容易地设定一个元素的宽高。 **注:**border-box 不包含 margin。
      inherit指定 box-sizing 属性的值,应该从父元素继承
      margin塌陷

      任何元素都可以设置border 设置宽高可能无效
      行内元素设置padding,margin上下是无效的,左右是有效的

      外边距合并:指的是,当两个垂直外边距相遇时,它们将形成一个外边距。
      合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
      外边距合并(叠加)是一个相当简单的概念。但是,在实践中对网页进行布局时,它会造成许多混淆。

      简单地说,外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
      当一个元素出现在另一个元素上面时,第一个元素的下外边距与第二个元素的上外边距会发生合并。请看下图:

      这里写图片描述

      当一个元素包含在另一个元素中时(假设没有内边距或边框把外边距分隔开),它们的上和/或下外边距也会发生合并。请看下图:
      这里写图片描述

      尽管看上去有些奇怪,但是外边距甚至可以与自身发生合并。
      假设有一个空元素,它有外边距,但是没有边框或填充。在这种情况下,上外边距与下外边距就碰到了一起,它们会发生合并:
      这里写图片描述
      如果这个外边距遇到另一个元素的外边距,它还会发生合并:
      这里写图片描述

      解决垂直外边距合并问题
      1. 为父元素定义上边框或者内边距
      2. 给父元素添加overflow:hidden
      3. 给最后面的元素加上浮动(left/right)
      4. 给最后一个元素加上display:inline-block;但是IE6和IE7下不完全支持display:inline-block,所以要加上*display:inline;zoom:1即可解决IE6、7的bug;
      宽高属性设置百分比

      子元素宽高设置百分比,是相对于父元素的包含块(一般是content区)来计算,即百分比*父元素包含块宽高

      css包含块的分析
      指出错误观念

      许多开发者认为一个元素的包含块就是他的父元素的内容区,其实这是错误的(至少不完全正确)!
      一个元素的尺寸和位置经常受其包含块的影响。大多数情况下,包含块就是这个元素最近的祖先块元素的内容区,但也不是总是这样。
      下面我们看看盒模型:
      当浏览器展示一个文档的时候,对于每一个元素,它都产生了一个盒子。每一个盒子都被划分为四个区域:
      \1. 内容区
      \2. 内边距区
      \3. 边框区
      \4. 外边距区

      img

      什么是包含块?

      包含块有分为根元素包含块和其他元素的包含块。

      根元素包含块

      根元素html的包含块是一个矩形,叫做初始化包含块(initial containing block)。
      可以看到html外面还有空间,这个包含html的块就被称为初始包含块(initial containing block),它是作为元素绝对定位和固定定位的参照物。
      对于连续媒体设备(continuous media),初始包含块的大小等于视口viewpor的大小,基点在画布的原点(视口左上角);对于分页媒体(paged media),初始包含块是页面区域(page area)。初始包含块的direction属性与根元素的相同。

      其他元素的包含块

      大多数情况下,包含块就是这个元素最近的祖先块元素的内容区,但也不是总是这样,下面就来学习如何确定这些元素的包含块。

      如何确定元素的包含块?

      确定包含块的过程完全依赖于这个包含块的 position 属性,大致分为下列场景:
      \1. 如果 position 属性是 static 或 relative 的话,包含块就是由它的最近的祖先块元素(比如说inline-block, block 或 list-item元素)或格式化上下文BFC(比如说 a table container, flex container, grid container, or the block container itself)的内容区的边缘组成的。
      \2. 如果 position 属性是 absolute 的话,包含块就是由它的最近的 position 的值不是 static (fixed, absolute, relative, or sticky)的祖先元素的内边距区的边缘组成的。
      \3. 如果 position 属性是 fixed 的话,包含块就是由 viewport (in the case of continuous media) or the page area (in the case of paged media) 组成的。
      \4. 如果 position 属性是 absolute 或 fixed,包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的:
      A transform or perspective value other than none
      A will-change value of transform or perspective
      A filter value other than none or a will-change value of filter (only works on Firefox).

      元素包含块的作用?

      元素的尺寸和位置经常受其包含块的影响。对于一个绝对定位的元素来说(他的 position 属性被设定为 absolute 或 fixed),如果它的 width, height, padding, margin, 和 offset 这些属性的值是一个比例值(如百分比等)的话,那这些值的计算值就是由它的包含块计算而来的。
      简单来说,如果某些属性被赋予一个百分值的话,它的计算值是由这个元素的包含块计算而来的。这些属性包括盒模型属性和偏移属性:
      \1. height, top, bottom 这些属性由包含块的 height 属性的值来计算它的百分值。如果包含块的 height 值依赖于它的内容,且包含块的 position 属性的值被赋予 relative 或 static的话,这些值的计算值为0。
      \2. width, left, right, padding, border,margin这些属性由包含块的 width 属性的值来计算它的百分值。
      说了这么多,其实只有在为当前元素设置百分比的长度样式时就必须要搞清楚当前元素的包含块是谁,然后再根据包含块元素的长度样式作为基数来计算当前元素的样式。

      下面示例公用HTML代码

      <body>
      <section>
        <p>This is a paragraph!</p>
      </section>
      </body>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      示例一

      CSS代码

      body {
      background: beige;
      }
      
      section {
      display: block;
      width: 400px;
      height: 160px;
      background: lightgray;
      }
      
      p {
      width: 50%;   /* == 400px * .5 = 200px */
      height: 25%;  /* == 160px * .25 = 40px */
      margin: 5%;   /* == 400px * .05 = 20px */
      padding: 5%;  /* == 400px * .05 = 20px */
      background: cyan;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      在这里,这个P标签position为默认的static,所以它的包含块为Section标签,通过我们的判断规则一来确定。

      img

      示例二

      CSS代码

      body {
      background: beige;
      }
      
      section {
      display: inline;
      background: lightgray;
      }
      
      p {
      width: 50%;     /* == half the body's width */
      height: 200px;  /* Note: a percentage would be 0 */
      background: cyan;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      在这里,这个P标签position为默认的static且它的父标签Section的display为inline,所以P标签的包含块为body标签,通过我们的判断规则一来确定。

      img

      示例三

      CSS代码

      body {
      background: beige;
      }
      
      section {
      transform: rotate(0deg);
      width: 400px;
      height: 160px;
      background: lightgray;
      }
      
      p {
      position: absolute;
      left: 80px;
      top: 30px;
      width: 50%;   /* == 200px */
      height: 25%;  /* == 40px */
      margin: 5%;   /* == 20px */
      padding: 5%;  /* == 20px */
      background: cyan;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

      在这里,这个P标签position为absolute且它的父标签Section的transform不为none,所以P标签的包含块为Section标签,通过我们的判断规则四来确定。

      img

      示例四

      CSS代码

      body {
      background: beige;
      }
      
      section {
      position: absolute;
      left: 30px;
      top: 30px;
      width: 400px;
      height: 160px;
      padding: 30px 20px;
      background: lightgray;
      }
      
      p {
      position: absolute;
      width: 50%;   /* == (400px + 20px + 20px) * .5 = 220px */
      height: 25%;  /* == (160px + 30px + 30px) * .25 = 55px */
      margin: 5%;   /* == (400px + 20px + 20px) * .05 = 22px */
      padding: 5%;  /* == (400px + 20px + 20px) * .05 = 22px */
      background: cyan;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      在这里,这个P标签position为absolute且它的父标签Section的position不为static,所以P标签的包含块为Section标签的padding边缘算起(前提是不能 box-sizing设置为border-box),通过我们的判断规则二来确定。

      img

      示例五

      CSS代码

      body {
      background: beige;
      }
      
      section {
      width: 300px;
      height: 300px;
      margin: 30px;
      padding: 15px;
      background: lightgray;
      }
      
      p {
      position: fixed;
      width: 50%;   /* == (50vw - (width of vertical scrollbar)) */
      height: 50%;  /* == (50vh - (height of horizontal scrollbar)) */
      margin: 5%;   /* == (5vw - (width of vertical scrollbar)) */
      padding: 5%;  /* == (5vw - (width of vertical scrollbar)) */
      background: cyan;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      在这里,这个P标签position为fixed,所以P标签的包含块为初始包含块(viewport),通过我们的判断规则三来确定。

      img

      网页布局

      标准流(普通流/文档流)
      浮动

      浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。

      **由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样(脱标,不占标准流的空间)。**具有行内块的特性;注意只能压住标准流盒子,不能压住标准流的文字,标准流文字会环绕浮动元素

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79d4Mon8-1646544115489)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220129163512848.png)]

      请看下图,当把框 1 向右浮动时,它脱离文档流并且向右移动,直到它的右边缘碰到包含框的右边缘:

      CSS 浮动实例 - 向右浮动的元素

      再请看下图,当框 1 向左浮动时,它脱离文档流并且向左移动,直到它的左边缘碰到包含框的左边缘。因为它不再处于文档流中,所以它不占据空间,实际上覆盖住了框 2,使框 2 从视图中消失。

      如果把所有三个框都向左移动,那么框 1 向左浮动直到碰到包含框,另外两个框向左浮动直到碰到前一个浮动框。

      CSS 浮动实例 - 向左浮动的元素

      如下图所示,如果包含框太窄,无法容纳水平排列的三个浮动元素,那么其它浮动块向下移动,直到有足够的空间。如果浮动元素的高度不同,那么当它们向下移动时可能被其它浮动元素“卡住”:

      CSS 浮动实例 2 - 向左浮动的元素

      浮动不占标准流的空间,但是当要浮动的元素上方有不浮动的元素时,浮动元素不会覆盖上面的元素,即浮动只会影响浮动盒子后面的标准流

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7PxrAXYM-1646544115491)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220128172306925.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QmlkaiYL-1646544115491)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220128172846547.png)]

      特点
      • 盖不住文本
      • 浮动元素后面不是块级元素,后面的元素将会和它并排(除非设置了元素的宽度,并且屏幕放不下时将会换行)
      • 浮动元素的上一个元素如果没有浮动,浮动只在当前行浮动;当浮动遇到浮动,它们将在一行排序,除非没有位置了
      • 当元素设置定位值为absolute、fixed时,浮动将被忽略
      • float引起父元素高度塌陷
      • 浮动元素会被后一个元素的margin-top影响
      float 属性

      在 CSS 中,我们通过 float 属性实现元素的浮动。

      如需更多有关 float 属性的知识,请访问参考手册:CSS float 属性

      行框和清理

      浮动框旁边的行框被缩短,从而给浮动框留出空间,行框围绕浮动框。

      因此,创建浮动框可以使文本围绕图像:

      行框围绕浮动框

      要想阻止行框围绕浮动框,需要对该框应用 clear 属性。clear 属性的值可以是 left、right、both 或 none,它表示框的哪些边不应该挨着浮动框。

      为了实现这种效果,在被清理的元素的上外边距上添加足够的空间,使元素的顶边缘垂直下降到浮动框下面:

      clear 属性实例 - 对行框应用 clear

      这是一个有用的工具,它让周围的元素为浮动元素留出空间。

      让我们更详细地看看浮动和清理。假设希望让一个图片浮动到文本块的左边,并且希望这幅图片和文本包含在另一个具有背景颜色和边框的元素中。您可能编写下面的代码:

      .news {
        background-color: gray;
        border: solid 1px black;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      <div class="news">
      <img src="news-pic.jpg" />
      <p>some text</p>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      这种情况下,出现了一个问题。因为浮动元素脱离了文档流,所以包围图片和文本的 div 不占据空间。

      如何让包围元素在视觉上包围浮动元素呢?需要在这个元素中的某个地方应用 clear:

      clear 属性实例 - 对空元素应用清理

      不幸的是出现了一个新的问题,由于没有现有的元素可以应用清理,所以我们只能添加一个空元素并且清理它。

      .news {
        background-color: gray;
        border: solid 1px black;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      .clear {
        clear: both;
        }
      
      <div class="news">
      <img src="news-pic.jpg" />
      <p>some text</p>
      <div class="clear"></div>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      这样可以实现我们希望的效果,但是需要添加多余的代码。常常有元素可以应用 clear,但是有时候不得不为了进行布局而添加无意义的标记。

      不过我们还有另一种办法,那就是对容器 div 进行浮动:

      .news {
        background-color: gray;
        border: solid 1px black;
        float: left;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      <div class="news">
      <img src="news-pic.jpg" />
      <p>some text</p>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      这样会得到我们希望的效果。不幸的是,下一个元素会受到这个浮动元素的影响。为了解决这个问题,有些人选择对布局中的所有东西进行浮动,然后使用适当的有意义的元素(常常是站点的页脚)对这些浮动进行清理。这有助于减少或消除不必要的标记。

      事实上,W3School 站点上的所有页面都采用了这种技术,如果您打开我们使用 CSS 文件,您会看到我们对页脚的 div 进行了清理,而页脚上面的三个 div 都向左浮动。

      方法

      额外标签法和伪元素法(:before和:after是在元素内部插入内容,需要设置display:block)均是设置一个占位标签,且占位标签和浮动元素不在同一行,即占位标签生成新行,所以额外标签法不用设置高度,伪元素高度设置成0

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QbysxAxT-1646544115493)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220130002247054.png)]

      方法一:使用带clear属性的空元素(额外标签法)

      在浮动元素后使用一个空元素如

      ,并在CSS中赋予.clear{clear:both;}属性即可清理浮动。亦可使用

      来进行清理。

      .news {
        background-color: gray;
        border: solid 1px black;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      .clear {
        clear: both;
        }
      
      <div class="news">
      <img src="news-pic.jpg" />
      <p>some text</p>
      <div class="clear"></div>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      优点:简单,代码少,浏览器兼容性好。

      缺点:需要添加大量无语义的html元素,代码不够优雅,后期不容易维护。

      方法二:使用CSS的overflow属性

      给浮动元素的容器添加overflow:hidden;或overflow:auto;可以清除浮动,另外在 IE6 中还需要触发 hasLayout ,例如为父元素设置容器宽高或设置 zoom:1。

      在添加overflow属性后,浮动元素又回到了容器层,把容器高度撑起,达到了清理浮动的效果。

      .news {
        background-color: gray;
        border: solid 1px black;
        overflow: hidden;
        *zoom: 1;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      <div class="news">
      <img src="news-pic.jpg" />
      <p>some text</p>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      方法三:给浮动的元素的容器添加浮动

      给浮动元素的容器也添加上浮动属性即可清除内部浮动,但是这样会使其整体浮动,影响布局,不推荐使用。

      方法四:使用邻接元素处理

      什么都不做,给浮动元素后面的元素添加clear属性。

      .news {
        background-color: gray;
        border: solid 1px black;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      .content{
        clear:both;
        }
      
      <div class="news">
      <img src="news-pic.jpg" />
      <p>some text</p>
      <div class="content"></div>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      方法五:使用CSS的:after伪元素

      结合 :after 伪元素(注意这不是伪类,而是伪元素,代表一个元素之后最近的元素)和 IEhack ,可以完美兼容当前主流的各大浏览器,这里的 IEhack 指的是触发 hasLayout。

      给浮动元素的容器添加一个clearfix的class,然后给这个class添加一个:after伪元素实现元素末尾添加一个看不见的块元素(Block element)清理浮动。

      .news {
        background-color: gray;
        border: solid 1px black;
        }
      
      .news img {
        float: left;
        }
      
      .news p {
        float: right;
        }
      
      .clearfix:after{
        content: "020"; 
        display: block; 
        height: 0; 
        clear: both; 
        visibility: hidden;  
        }
      
      .clearfix {
        /* 触发 hasLayout */ 
        zoom: 1; 
        }
      
      <div class="news clearfix">
      <img src="news-pic.jpg" />
      <p>some text</p>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30

      通过CSS伪元素在容器的内部元素最后添加了一个看不见的空格"020"或点".",并且赋予clear属性来清除浮动。需要注意的是为了IE6和IE7浏览器,要给clearfix这个class添加一条zoom:1;触发haslayout。

      方法五:使用CSS的:after,:before双伪元素

      定位

      top、bottom、left、right

      static 定位

      HTML 元素的默认值,即没有定位,遵循正常的文档流对象。

      静态定位的元素不会受到 top, bottom, left, right影响。

      div.static { position: static; border: 3px solid #73AD21; }


      fixed 定位

      元素的位置相对于浏览器可视窗口是固定位置。即使窗口是滚动的它也不会移动:

      p.pos_fixed { position:fixed; top:30px; right:5px; }

      Fixed定位使元素的位置与文档流无关,因此不占据空间

      Fixed定位的元素和其他元素重叠。


      relative 定位

      相对定位元素的定位是相对其正常位置。

      h2.pos_left { position:relative; left:-20px; } h2.pos_right { position:relative; left:20px; }

      移动相对定位元素,但它原本所占的空间不会改变

      h2.pos_top { position:relative; top:-50px; }

      相对定位元素经常被用来作为绝对定位元素的容器块。(当绝对定位元素的父元素)


      absolute 定位

      绝对定位的元素的位置相对于最近的已定位的父元素或者祖先元素(static不算定位),如果元素没有已定位的父元素或者祖先元素,那么它的位置相对于:

      h2 { position:absolute; left:100px; top:150px; }

      absolute 定位使元素的位置与文档流无关,因此不占据空间

      absolute 定位的元素和其他元素重叠。


      sticky 定位

      sticky 英文字面意思是粘,粘贴,所以可以把它称之为粘性定位。

      position: sticky; 基于用户的滚动位置来定位。

      粘性定位的元素是依赖于用户的滚动,在 position:relativeposition:fixed 定位之间切换。

      它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。

      元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。

      这个特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。

      注意: Internet Explorer, Edge 15 及更早 IE 版本不支持 sticky 定位。 Safari 需要使用 -webkit- prefix (查看以下实例)。

      div.sticky { position: -webkit-sticky; /* Safari */ position: sticky; top: 0; background-color: green; border: 2px solid #4CAF50; }


      重叠的元素

      元素的定位与文档流无关,所以它们可以覆盖页面上的其它元素

      z-index属性(必须在定位元素中使用)指定了一个元素的堆叠顺序(哪个元素应该放在前面,或后面)

      一个元素可以有正数或负数的堆叠顺序:

      img { position:absolute; left:0px; top:0px; z-index:-1; }

      具有更高堆叠顺序的元素总是在较低的堆叠顺序元素的前面。

      注意: 如果两个定位元素重叠,没有指定z - index,最后定位在HTML代码中的元素将被显示在最前面,后写的在上面。

      隐藏

      visibility:hidden可以隐藏某个元素,但隐藏的元素仍需占用与未隐藏之前一样的空间。也就是说,该元素虽然被隐藏了,但仍然会影响布局。

      display:none可以隐藏某个元素,且隐藏的元素不会占用任何空间。也就是说,该元素不但被隐藏了,而且该元素原本占用的空间也会从页面布局中消失。

      文本居中

      vertical-align:1.单个元素内部对齐;2.当对行内元素和行内块元素生效,需要多个元素一起使用

      <div id="" style="height: 6.25rem;background-color: blue;">
      	<div id=""
      		style="width: 100px;height: 100%;border-radius: 25px;background-color: aqua;vertical-align: middle;display: inline-block;">
      				div标签
      	</div>
      	<div id=""
      		style="width: 100px;height: 50px;border-radius: 25px;background-color: aqua;vertical-align: middle;display: inline-block;">
      				div标签
      	</div>
      </div>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      描述
      baseline默认。元素放置在父元素的基线上。
      sub垂直对齐文本的下标。
      super垂直对齐文本的上标
      top把元素的顶端与行中最高元素的顶端对齐
      text-top把元素的顶端与父元素字体的顶端对齐
      middle把此元素放置在父元素的中部。
      bottom使元素及其后代元素的底部与整行的底部对齐。
      text-bottom把元素的底端与父元素字体的底端对齐。
      length将元素升高或降低指定的高度,可以是负数。
      %使用 “line-height” 属性的百分比值来排列此元素。允许使用负值。
      inherit规定应该从父元素继承 vertical-align 属性的值。

      BFC布局

      css3

      2D转换

      转换后不会影响原有布局,原有位置保留,转换元素,但它原本所占的空间不会改变。(类似于relative定位)

      translate,translateX,translateY对行内元素无效

      函数描述
      matrix(n,n,n,n,n,n)定义 2D 转换,使用六个值的矩阵。
      translate(x,y)定义 2D 转换,沿着 X 和 Y 轴移动元素。x、y为百分数时为自身宽高的百分比
      translateX(n)定义 2D 转换,沿着 X 轴移动元素。n为百分数时为自身宽的百分比
      translateY(n)定义 2D 转换,沿着 Y 轴移动元素。n为百分数时为自身高的百分比
      scale(x,y)定义 2D 缩放转换,改变元素的宽度和高度。
      scaleX(n)定义 2D 缩放转换,改变元素的宽度。
      scaleY(n)定义 2D 缩放转换,改变元素的高度。
      rotate(angle)定义 2D 旋转,在参数中规定角度。
      skew(x-angle,y-angle)定义 2D 倾斜转换,沿着 X 和 Y 轴。
      skewX(angle)定义 2D 倾斜转换,沿着 X 轴。
      skewY(angle)定义 2D 倾斜转换,沿着 Y 轴。

      transform简写时顺序若有位移先写位移(先旋转会改变坐标轴)

      3D转换
      动画

      定义动画

      //使用%来划分动画间隔
      @keyframes myfirst
      {
          0%   {background: red;}
          25%  {background: yellow;}
          50%  {background: blue;}
          100% {background: green;}
      }
      //或者使用from to
      @keyframes myfirst
      {
          from {background: red;}
          to {background: yellow;}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      调用动画

      div
      {
      	animation:myfirst 5s;  //调用动画
      	-moz-animation:myfirst 5s; /* Firefox */
      	-webkit-animation:myfirst 5s; /* Safari and Chrome */
      	-o-animation:myfirst 5s; /* Opera */
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      Less基础

      1. 维护CSS的弊端

      CSS是一门非程序式语言,没有变量、函数、SCOPE(作用域)等概念

      • CSS冗余度比较高
      • 不方便维护及扩展,不利于复用
      • CSS没有很好的计算能力

      2. Less介绍

      Less(Leaner Style Sheets)的缩写,是一门CSS扩展语言,也称为CSS预处理器

      Less在CSS的语法基础上,引入了变量,Mixin(混入),运算以及函数等功能,大大简化了CSS的编写,降低了CSS的维护成本

      Less中文网址:http://lesscss.cn/

      常见的CSS预处理器:Sass、Less、Stylus

      总结:Less是一门CSS预处理语言,它扩展了CSS的动态特性

      3. Less安装

      • 安装nodejs,下载LTS稳定版本,网址:https://nodejs.org/en/download/
      • 检查是否安装成功,使用cmd命令(win10是window + r打开,运行输入cmd)——输入"node -v"查看版本即可
      • 基于node.js在线安装Less,使用cmd命令"npm install -g less"即可
      • 检查是否安装成功,使用cmd命令"lessc -v"查看版本即可

      4. Less使用

      首先新建一个后缀名为.less的文件,在这个.less文件里面书写Less语句

      Less变量、Less编译、Less嵌套、Less运算

      5. Less变量

      语法:@变量名: 值;

      变量命名规范:必须有@为前缀、不能包含特殊符号、不能以数字开头、大小写敏感

      使用规范:body {color: @color;}

      6. Less编译

      Less包含一套自定义的语法及一个解析器,用户根据这些语法定义自己的样式规则,这些规则最终通过解析器编译成对应的CSS文件

      nodejs方法:在当前文件夹,使用cmd命令“lessc style.less > style.css”

      vscode插件:Easy LESS插件(只要保存一下Less文件,会自动生成CSS文件)

      7. Less嵌套

      子元素的样式直接写到父元素里面

      .header {
          width: 200px;
          .logo {
              width: 100px;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      如果遇见交集 / 伪类 / 伪元素选择器,内层选择器的前面需要加&符号,被解析为父元素自身或父元素的伪类(若没有&符号,会被解析为父选择器的后代)

      a{
          &.box {
              color: red;
          }
          &:hover {
              color: blue;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      8. Less运算

      任何数字、颜色或者变量都可以参与运算,Less提供了+ - * / 算术运算

      @width: 10px + 5;
      div {
          width: (@width + 5) * 2;
          height: (300px / 50);
          border: @width solid red;
          background-color: #999 - #333;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      注意事项:

      • less运算符左右必须加空格隔开
      • 两个数参与运算,如果只有一个数有单位,则最后结果就以这个单位为准
      • 两个数参与运算,如果两个数都有单位,而且不一样的单位,最后结果以第一个单位为准

      移动端

      窗口适配

      原因(不准确,仅供参考,记住结果就行):html中度量的单位 用px来计算,在pc中往往 1 css px = 1 物理像素,css像素时抽象和相对的了,在不同设备中1px对应不同的设备像素;iphone3分辨率是320*480 即 css 1px = 1个物理像素;iphone4 分辨率640x960但屏幕尺寸没有改变,意味着同一块区域像素多了1倍 即 css 1px =2个物理像素(现在大部分手机都是 css 1px =2个物理像素); 物理像素表示每英寸所拥有的像素数目,数值越高,代表屏幕能够以更高的密度来显示图像。

      总的来说就是:pc端通常是1px=1物理像素,移动端通常1px=2个物理像素,1rpx=1物理像素。举例:pc端为980px的网页在移动端为375px上显示自然会缩小。

      移动端px显示的界面会小,rpx正常显示

      PC端、移动端的页面适配及兼容处理 - 简书 (jianshu.com)

      pc端的网页在移动端打开时会缩小,所以用原生的html写移动端网页需要加下面标签用以适配,若用uniapp框架不用加(使用的rpx,1rpx=1物理像素=0.5px)

      • viewport:能优化移动浏览器的显示。如果不是响应式网站,不要使用initial-scale或者禁用缩放。
        大部分4.7-5寸设备的viewport宽设为360px;5.5寸设备设为400px;iphone6设为375px;ipone6 plus设为414px。
      <meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
      <!-- `width=device-width` 会导致 iPhone 5 添加到主屏后以 WebApp 全屏模式打开页面时出现黑边  -->
      
      • 1
      • 2
      1. width:宽度(数值 / device-width)(范围从200 到10,000,默认为980 像素)
      2. height:高度(数值 / device-height)(范围从223 到10,000)
      3. initial-scale:初始的缩放比例 (范围从>0 到10)
      4. minimum-scale:允许用户缩放到的最小比例
      5. maximum-scale:允许用户缩放到的最大比例
      6. user-scalable:用户是否可以手动缩 (no,yes)
      7. minimal-ui:可以在页面加载时最小化上下状态栏。(已弃用)

      注意,很多人使用initial-scale=1到非响应式网站上,这会让网站以100%宽度渲染,用户需要手动移动页面或者缩放。如果和initial-scale=1同时使用user-scalable=no或maximum-scale=1,则用户将不能放大/缩小网页来看到全部的内容。

      特殊样式

      -webkit-tap-highlight-color:transparent //取消点击高亮

      流式布局(百分比布局)

      通常设置body宽度为100%,其他需要适应屏幕变化的子元素设置为百分比

      flex布局

      Flex 布局语法教程 | 菜鸟教程 (runoob.com)

      一、Flex布局是什么?

      Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。

      任何一个容器都可以指定为Flex布局。

      .box{
        display: flex;
      }
      
      • 1
      • 2
      • 3

      行内元素也可以使用Flex布局。

      .box{
        display: inline-flex;
      }
      
      • 1
      • 2
      • 3

      Webkit内核的浏览器,必须加上-webkit前缀。

      .box{
        display: -webkit-flex; /* Safari */
        display: flex;
      }
      
      • 1
      • 2
      • 3
      • 4

      注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。

      二、基本概念

      采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。

      img

      容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。

      项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。

      三、容器(父元素)的属性

      以下6个属性设置在容器上。

      • flex-direction
      • flex-wrap
      • flex-flow
      • justify-content
      • align-items
      • align-content
      3.1 flex-direction属性

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

      .box {
        flex-direction: row | row-reverse | column | column-reverse;
      }
      
      • 1
      • 2
      • 3

      img

      它可能有4个值。

      • row(默认值):主轴为水平方向,起点在左端。
      • row-reverse:主轴为水平方向,起点在右端。
      • column:主轴为垂直方向,起点在上沿。
      • column-reverse:主轴为垂直方向,起点在下沿。
      3.2 flex-wrap属性

      默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

      img

      .box{
        flex-wrap: nowrap | wrap | wrap-reverse;
      }
      
      • 1
      • 2
      • 3

      它可能取三个值。

      (1)nowrap(默认):不换行。

      img

      (2)wrap:换行,第一行在上方。

      img

      (3)wrap-reverse:换行,第一行在下方。

      img

      3.3 flex-flow

      flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。

      .box {
        flex-flow: <flex-direction> <flex-wrap>;
      }
      
      • 1
      • 2
      • 3
      3.4 justify-content属性

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

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

      img

      它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。

      • flex-start(默认值):左对齐
      • flex-end:右对齐
      • center: 居中
      • space-between:两端对齐,项目之间的间隔都相等。
      • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
      3.5 align-items属性

      align-items属性定义项目在交叉轴上如何对齐。

      .box {
        align-items: flex-start | flex-end | center | baseline | stretch;
      }
      
      • 1
      • 2
      • 3

      img

      它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

      • flex-start:交叉轴的起点对齐。
      • flex-end:交叉轴的终点对齐。
      • center:交叉轴的中点对齐。
      • baseline: 项目的第一行文字的基线对齐。
      • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
      3.6 align-content属性

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

      .box {
        align-content: flex-start | flex-end | center | space-between | space-around | stretch;
      }
      
      • 1
      • 2
      • 3

      img

      该属性可能取6个值。

      • flex-start:与交叉轴的起点对齐。
      • flex-end:与交叉轴的终点对齐。
      • center:与交叉轴的中点对齐。
      • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
      • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
      • stretch(默认值):轴线占满整个交叉轴。
      align-items和align-content的区别

      https://blog.csdn.net/sinat_27088253/article/details/51532992

      四、项目(子元素)的属性

      以下6个属性设置在项目上。

      • order
      • flex-grow
      • flex-shrink
      • flex-basis
      • flex
      • align-self
      4.1 order属性

      order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

      .item {
        order: <integer>;
      }
      
      • 1
      • 2
      • 3

      img

      4.2 flex-grow属性

      flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

      .item {
        flex-grow: <number>; /* default 0 */
      }
      
      • 1
      • 2
      • 3

      img

      如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

      4.3 flex-shrink属性

      flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

      .item {
        flex-shrink: <number>; /* default 1 */
      }
      
      • 1
      • 2
      • 3

      img

      如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

      负值对该属性无效。

      4.4 flex-basis属性

      flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

      .item {
        flex-basis: <length> | auto; /* default auto */
      }
      
      • 1
      • 2
      • 3

      它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。

      4.5 flex属性

      flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

      .item {
        flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
      }
      
      • 1
      • 2
      • 3

      该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

      建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

      4.6 align-self属性

      align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

      .item {
        align-self: auto | flex-start | flex-end | center | baseline | stretch;
      }
      
      • 1
      • 2
      • 3

      img

      该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

      rem适配布局

      1. rem单位

      rem(root em)是一个相对单位,类似于em,em是相对于父元素字体大小

      rem的基准是相对于html元素的字体大小

      rem的优势:整个页面只有一个html,可以通过修改html里面的字体大小来改变页面中元素的大小,可以整体控制

      2.媒体查询

      CSS3 多媒体查询 | 菜鸟教程 (runoob.com)

      媒体查询(Media Query),CSS3的新语法

      • @media查询,可以针对不同的媒体类型定义不同的样式
      • @media可以针对不同的屏幕尺寸设置不同的样式
      • 当重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面
      1. 语法规范
      @media mediatype and|not|only (media feature) { CSS-Code; }
      
      • 1

      注意:@media开头,media feature媒体特性必须有小括号包含

      2. mediatype 媒体类型

      将不同的终端设备划分成不同的类型,称为媒体类型

      值及解释说明
      all:用于所有设备
      print:用于打印机和打印预览
      screen:用于电脑屏幕,平板电脑,智能手机等

      3. 关键字

      关键字将媒体类型或多个媒体特性连接到一起作为媒体查询的条件

      and:可以将多个媒体特性连接到一起,相当于“且”的意思
      not:排除某个媒体类型,相当于“非”的意思,可以省略
      or:可以测试多个媒体查询的条件,只要有一个条件成立,就执行,“或”的意思
      only:指定某个特定的媒体类型,可以省略

      4. 媒体特性

      根据不同媒体类型的媒体特性设置不同的展示风格,先了解三个,注意加小括号包含

      width:定义输出设备中页面可见区域的宽度
      min-width:定义输出设备中页面最小可见区域的宽度
      max-width:定义输出设备中页面最大可见区域的宽度

      媒体查询+rem实现元素动态大小变化

      rem单位是跟着html来走的,有了rem页面元素可以设置不同大小尺寸

      媒体查询可以根据不同设备宽度来修改样式

      媒体查询+rem就可以实现不同设备宽度,实现页面元素大小的动态变化

      rem适配方案
      1. 适配的目标

      让一些不能等比自适应的元素,达到当设备尺寸发生改变时,等比例适配当前设备

      2. 如何达到适配的目的

      使用媒体查询根据不同设备按比例设置html的字体大小,然后页面元素使用rem做尺寸单位,当html字体大小变化元素尺寸也会发生变化,从而达到等比缩放的适配

      3. rem实际开发适配方案
      • 按照设计稿与设备宽度的比例,动态计算并设置html根标签的font-size大小(媒体查询)
      • CSS中,设计稿元素的宽、高、相对位置等取值,按照同等比例换算为rem为单位的值
      4. rem适配方案技术使用(市场主流)
      • less + 媒体查询 + rem
      • flexible.js + rem(推荐,更简单)

      框架

      Bootstrap框架

      ant-design

      uniapp

      JavaScript

      弱类型语言,即变量的数据类型由=右边的值动态确定,执行过程中可以变化

      解释性语言,即解释一行执行一行

      单线程

      JavaScript基础语法-dom-bom-js-es6新语法-jQuery-数据可视化echarts黑马pink老师前端入门基础视频教程(500多集)持续_哔哩哔哩_bilibili

      (73条消息) JavaScript单线程的运行机制_问白的博客-CSDN博客_javascript 单线程执行

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KdSbkaix-1646544115497)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207174457120.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0uKk8PFL-1646544115498)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207175617273.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nCaUsXvT-1646544115498)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207174524476.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7NMGkITF-1646544115499)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207175312073.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sMcJ6e6C-1646544115499)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207175224236.png)]

      null和undefined

      undefined:

      在 JavaScript 中, undefined 是一个没有设置值的变量。

      typeof 一个没有值的变量会返回 undefined。

      null:

      在 JavaScript 中 null 表示 “什么都没有”。

      null是一个只有一个值的特殊类型。表示一个空对象引用。

      undefined和null的区别:

      ● undefined表示一个变量没有被声明,或者被声明了但没有被赋值(未初始化),一个没有传入实参的形参变量的值为undefined,如果一个函数什么都不返回,则该函数默认返回undefined。null则表示“什么都没有”,即“空值”。

      ● Javascript将未赋值的变量默认值设为undefined;Javascript从来不会将变量设为null。它是用来让程序员表明某个用var声明的变量时没有值的;

      ● undefined不是一个有效的JSON,而null是;

      ● nullundefined 的值相等,但类型不等:undefined的类型(typeof)是undefined;null的类型(typeof)是object

      null == undefined            // true
      null === undefined           // false
      
      typeof undefined             // undefined
      typeof null                  // object
      
      • 1
      • 2
      • 3
      • 4
      • 5

      ● nullundefined之间的主要区别在于它们被转换为原始类型的方式。

      在’null’上执行算术转换时,则值为0,可以使用以下代码片段验证此转换。

      var v1= 5+ null;
      console.log(v1)
      
      • 1
      • 2

      执行时,此代码的将输出

      5
      
      • 1

      但是,“undefined”不执行任何此类转换。如果您尝试将“undefined”添加到数字中,您将获得NaN或Not-a-Number。以下代码片段说明了“undefine”的这一方面。

      var v2= 5+ undefined;
      console.log(v2)
      
      • 1
      • 2

      执行时,代码将输出:

      NaN
      
      • 1
      null == 0
      //false
      null == ""
      //false
      null == false
      //false
      undefined == 0
      //false
      undefined == ""
      //false
      undefined == false
      //false
      undefined == null  //注意!注意!注意!
      //true
      undefined === null  //注意!注意!注意!
      //false
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      其他类型转bool

      ‘’、NaN、null、0、undefined为false,其他为true

      浮点数精度问题

      JavaScript 浮点数运算的精度问题 - 知乎 (zhihu.com)

      // 加法 =====================
      // 0.1 + 0.2 = 0.30000000000000004
      // 0.7 + 0.1 = 0.7999999999999999
      // 0.2 + 0.4 = 0.6000000000000001
      // 2.22 + 0.1 = 2.3200000000000003
       
      // 减法 =====================
      // 1.5 - 1.2 = 0.30000000000000004
      // 0.3 - 0.2 = 0.09999999999999998
       
      // 乘法 =====================
      // 19.9 * 100 = 1989.9999999999998
      // 19.9 * 10 * 10 = 1990
      // 1306377.64 * 100 = 130637763.99999999
      // 1306377.64 * 10 * 10 = 130637763.99999999
      // 0.7 * 180 = 125.99999999999999
      // 9.7 * 100 = 969.9999999999999
      // 39.7 * 100 = 3970.0000000000005
       
      // 除法 =====================
      // 0.3 / 0.1 = 2.9999999999999996
      // 0.69 / 10 = 0.06899999999999999
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      =

      两等号判等,会在比较时进行类型转换;
      三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);

      短路运算符&&、||

      A&&B,A为真时B才参与运算,A为假时B不再参与运算

      A||B,A为假时B才参与运算,A为真时B不再参与运算

      函数

      函数的形参个数=实参个数,正常输出

      函数的形参个数<实参个数,只取到形参个数

      函数的形参个数>实参个数,多余的形参定义为undefined

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Kj7Wt6c-1646544115499)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220205132851467.png)]

      函数声明
      命名函数

      function 函数名() {}

      匿名函数

      var 函数名=function() {}

      arguments(伪数组)

      简单来说:arguments 是一个对应于传递给函数的参数的类数组对象

      arguments 对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments 对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:

      arguments[0]
      arguments[1]
      arguments[2]
      复制代码
      
      • 1
      • 2
      • 3
      • 4

      参数也可以被设置:

      arguments[0] = 'value';
      复制代码
      
      • 1
      • 2

      arguments 是一个对象,不是一个 Array 。它类似于Array ,但除了length属性和索引元素之外没有任何Array 属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array

      所以经常能看到这样的代码:

      // 由于arguments不是 Array,所以无法使用 Array 的方法,所以通过这种方法转换为数组
       
      var args = [].slice.call(arguments);  // 方式一
      var args = Array.prototype.slice.call(arguments); // 方式二
       
      // 下面是 es6 提供的语法
      let args = Array.from(arguments)   // 方式一
      let args = [...arguments]; // 方式二
      复制代码
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      arguments上的属性
      • arguments.callee:指向当前执行的函数(在 严格模式 下,第5版 ECMAScript (ES5) 禁止使用 arguments.callee()
      • argunments.length:指向传递给当前函数的参数数量
      • arguments.caller:已移除
      arguments与剩余参数、默认参数和解构赋值参数的结合使用
      1. 在严格模式下,剩余参数默认参数解构赋值参数的存在不会改变 arguments对象的行为,但是在非严格模式下就有所不同了
      function func(a) { 
        arguments[0] = 99;   // 更新了arguments[0] 同样更新了a
        console.log(a);
      }
      func(10); // 99
       
      // 并且
       
      function func(a) { 
        a = 99;              // 更新了a 同样更新了arguments[0] 
        console.log(arguments[0]);
      }
      func(10); // 99
      复制代码
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      1. 当非严格模式中的函数没有包含剩余参数默认参数解构赋值,那么arguments对象中的值跟踪参数的值(反之亦然)。看下面的代码:
      function func(a = 55) { 
        arguments[0] = 99; // updating arguments[0] does not also update a
        console.log(a);
      }
      func(10); // 10
       
      //
       
      function func(a = 55) { 
        a = 99; // updating a does not also update arguments[0]
        console.log(arguments[0]);
      }
      func(10); // 10
       
       
      function func(a = 55) { 
        console.log(arguments[0]);
      }
      func(); // undefined
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      作用域

      局部变量:在函数中通过var声明的变量。代码块运行结束后就会被销毁

      function func(){
      	var temp=10
      }
      
      • 1
      • 2
      • 3

      全局变量:在函数外通过var声明的变量。浏览器关闭时才销毁

      var temp=10
      
      • 1

      没有声明就使用的变量,默认为全局变量,不论这个变量在哪被使用。

      //函数外直接使用
      temp=10
      //函数内直接使用
      function func(){
      	temp=10
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      (es6)块级作用域:const和let;let 的声明方式与 var 相同,用 let 来代替 var 来声明变量,就可以把变量限制在当前代码块中。

      {
      	let temp=10
      }
      console.log(temp)//报错
      {
      	const temp=10
      }
      console.log(temp)//报错
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      作用域链

      作用域链其实是一个很简单的概念,当我们使用一个变量时,先在当前作用域查找,如果没找到就去他外层作用域查找,如果还没有,就再继续往外找,一直找到全局作用域,如果最终都没找到,就报错。比如如下代码:

      let x = 1;
      
      function f() {
        function f1() {
          console.log(x);
        }
      
        f1();
      }
      
      f();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      这段代码在f1中输出了x,所以他会在f1中查找这个变量,当然没找到,然后去f中找,还是没找到,再往上去全局作用域找,这下找到了。这个查找链条就是作用域链。

      声明提前(预解析)

      原理:只提升声明,不提升赋值

      var a=b=c=9;
      //等价于
      var a=9;
      b=9;
      c=9;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      变量声明提前

      在ES6之前,我们申明变量都是使用var,使用var申明的变量都是函数作用域,即在函数体内可见,这会带来的一个问题就是申明提前。

      var x = 1;
      function f() {
        console.log(x);
        var x = 2;
      }
      
      f();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      上述代码的输出是undefined,因为函数f里面的变量x使用var申明,所以他其实在整个函数f可见,也就是说,他的声明相当于提前到了f的最顶部,但是赋值还是在运行的x = 2时进行,所以在var x = 2;上面打印x就是undefined,上面的代码其实等价于:

      var x = 1;
      function f() {
        var x
        console.log(x);
        x = 2;
      }
      
      f();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      函数声明提前

      看下面这个代码:

      function f() {
        x();
      
        function x() {
          console.log(1);
        }
      }
      
      f();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      上述代码x()调用是可以成功的,因为函数的声明也会提前到当前函数的最前面,也就是说,上面函数x会提前到f的最顶部执行,上面代码等价于:

      function f() {
        function x() {
          console.log(1);
        }
      
        x();
      }
      
      f();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      但是有一点需要注意,上面的x函数如果换成函数表达式就不行了:

      function f() {
        x();
      
        var x = function() {
          console.log(1);
        }
      }
      
      f();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      这样写会报错Uncaught TypeError: x is not a function。因为这里的x其实就是一个普通变量,只是它的值是一个函数,它虽然会提前到当前函数的最顶部申明,但是就像前面讲的,这时候他的值是undefined,将undefined当成函数调用,肯定就是TypeError

      变量申明和函数申明提前的优先级

      既然变量申明和函数申明都会提前,那谁的优先级更高呢?答案是**函数申明的优先级更高!**看如下代码:

      var x = 1;
      function x() {}
      
      console.log(typeof x);  // number
      
      • 1
      • 2
      • 3
      • 4

      上述代码我们申明了一个变量x和一个函数x,他们拥有同样的名字。最终输出来的typeofnumber,说明函数申明的优先级更高,x变量先被申明为一个函数,然后当我们再用var申明x的时候,这个var会被忽略,但是x=1的赋值语句会运行,最后x就是1,类型是number

      对象

      创建
      //创建空对象
      var obj={}
      //创建空对象
      var obj=new Object()
      
      • 1
      • 2
      • 3
      • 4
      构造函数创建(类似于java的类)

      ​ 创建一个构造函数,专门用来创建Person对象的,构造函数就是一个普通的函数,创建对象和普通函数没有区别,不同的是构造函数习惯上首字母大写

      构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
      
      构造函数执行流程:
      1.立刻创建一个新的对象
      2.将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
      3.逐行执行函数中的代码
      4.将新建的对象作为返回值返回
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      function Person(name,age,gender){
          this.name = name;
          this.age = age;
          this.gender = gender;
          this.sayName = function(){
              alert(this.name)
          }
      }
      var per =new Person("Tom",12,"男");
      var per1 =new Person("LiLei",22,"男");
      var per2 =new Person("Jenny",12,"女");
      console.log(per);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IH0DgLFz-1646544115500)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220205155614579.png)]

      使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类,我们将通过一个构造函数创建的对象,称为是该类的实例

      this的三种情况:
          1.当以函数的形式调用时,this是window
          2.当以方法的形式调用时,谁调用方法this就是谁
          3.当以构造函数的形式调用时,this就是新创建的那个对象
      
      • 1
      • 2
      • 3
      • 4
      new操作符具体干了什么呢?
           1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
           2、属性和方法被加入到 this 引用的对象中。
           3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
      
      var obj  = {};
      obj.__proto__ = Base.prototype;
      Base.call(obj);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8FEycvL-1646544115500)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220205164301519.png)]

      this指向问题

      js中谁调用指向谁

      如:全局中,func()=window.func()中this指向window

      btn.sayHi()中this指向btn

      es6箭头函数:箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。

      (73条消息) js中的this指向问题_qq_45225833的博客-CSDN博客

      [箭头函数](#2. 箭头函数)
      访问

      对象里的方法可以通过this访问对象属性

      var obj={
      	name:"liu",
      	say:function(){
      		console.log(this.name)
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      字符串

      基本包装类型,就是把简单数据类型包装成了复杂数据类型

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DzFkalvf-1646544115501)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206004747656.png)]

      不可变

      修改某一个变量(String类型)的值时,实际上修改的是地址,修改后该变量指向一个新的内存空间,原有的内存空间里面的值不变。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NZ2UDEuO-1646544115501)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206005448142.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IohNx9U2-1646544115501)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206005724380.png)]

      数据类型

      JS中的数据类型主要分为两大类:原始类型(值类型)和引用类型。常见的数据类型如下图所示:

      image-20200506103537269

      原始数据类型存在栈中,引用类型在栈中存的是一个引用地址,这个地址指向的是堆中的一个数据对象。需要注意的是null在这里我们算在原始类型里面,但是你用typeof的时候会发现他是object,原因是就算他是一个对象,那他应该在栈中存一个引用地址,但是他是一个空对象,所以这个地址为空,也就是不对应堆中的任意一个数据,他在堆中没有数据,只存在于栈中,所以这里算为了原始类型。引用类型其实主要就是ObjectArrayFunction这些其实也都是Object派生出来的。关于这两种类型在内存中的更详细的知识可以看这篇文章。

      image-20200506104330145

      下面我们来看看这两种类型的区别:

      原始类型(简单数据类型)
      1. 原始类型的值无法更改,要更改只能重新赋值。像下面这样尝试去修改是不行的,但是整个重新赋值可以。

        image-20200506104958681

        image-20200506105044457

      2. 原始类型的比较就是比较值,值相等,他们就相等

      引用类型(复杂数据类型)
      1. 引用类型的值是可以修改的,注意这个时候我们虽然修改了a里面的属性,但是a在栈上的引用地址并没有变化,变化的是堆中的数据。

        image-20200506105513907

      2. 引用类型的比较是比较他们的索引地址,而不是他们的值。比如下面两个对象,看着是一样的,但是他们的引用地址不一样,其实是不等的:

        image-20200506110135018

        要想让他们相等,得直接将b赋值为a,这样他们的引用地址一样,就是相等的。

        image-20200506110256501

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDvNNPjo-1646544115504)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206011653408.png)]

      传参时的区别
      1. 简单数据类型

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UV86qi1H-1646544115505)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206013542876.png)]

      function func(a){}

      var x=10;

      func(x);

      本质是x复制一份赋值给a,修改a的值不会影响x

      1. 引用类型

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nZBCStxw-1646544115505)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206013456888.png)]

      function func(a){}

      var x={};

      func(x);

      此时x在栈中存放的是最终对象的地址,传参时是把x(最终对象的地址)赋值给a,此时a和x在栈中存放的地址相同,所以最终指向的对象相同,所以修改a也会影响x

      Web API(DOM和BOM)

      DOM

      在 HTML DOM (Document Object Model) 中 , 每一个元素都是 节点:

      • 文档是一个文档节点。
      • 所有的HTML元素都是元素节点。
      • 所有 HTML 属性都是属性节点。
      • 文本插入到 HTML 元素是文本节点。are text nodes。
      • 注释是注释节点。

      通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML。

      • JavaScript 能够改变页面中的所有 HTML 元素
      • JavaScript 能够改变页面中的所有 HTML 属性
      • JavaScript 能够改变页面中的所有 CSS 样式
      • JavaScript 能够对页面中的所有事件做出反应
      元素对象方法
      innerText和innerHTML

      innerText不会识别html标签

      innerHTML识别html标签

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-snXDrfnP-1646544115506)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206165556465.png)]

      获取元素属性

      element.属性:获取元素的内置属性,即元素本身自带的属性

      element.getAttribute(‘属性’):除了内置属性外,还可以获取自定义属性

      设置属性

      element.属性=:设置元素的内置属性,即元素本身自带的属性

      element.setAttribute(attributename,attributevalue):除了内置属性外,还可以设置自定义属性

      三种动态创建元素区别

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2eCbreK3-1646544115506)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206220904851.png)]

      事件

      传统的添加事件,后面的会覆盖前面的,具有唯一性

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s31DoAeg-1646544115506)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206222119788.png)]

      addEventListener() 添加可以添加多个事件

      DOM事件流

      捕获:由外向内

      冒泡:由内向外

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i835UsWI-1646544115507)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206223450064.png)]

      addEventListener才能设置捕获,其他的方式只有冒泡

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tPRO7wZ4-1646544115507)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206230745671.png)]

      e.target:指的是触发事件的元素,this是绑定事件的元素

      阻止冒泡

      e.stopPropagation()

      事件委托

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rg3xmPAh-1646544115507)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206232757750.png)]

      键盘事件

      e.keyCode获取键盘编码

      属性描述DOM
      onkeydown某个键盘按键被按下。不区分字母大小写2
      onkeypress某个键盘按键被按下并松开。区分字母大小写2
      onkeyup某个键盘按键被松开。不区分字母大小写2
      BOM

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LG1jwKiY-1646544115508)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207162656511.png)]

      BOM包含DOM

      事件

      HTML 事件 | 菜鸟教程 (runoob.com)

      HTML DOM 事件对象 | 菜鸟教程 (runoob.com)

      Window 对象 | 菜鸟教程 (runoob.com)

      offset与style

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhOKZyXC-1646544115508)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220208001935441.png)]

      闭包

      什么是闭包

      闭包就是能够读取其他函数内部变量的函数,
      由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,
      因此可以把闭包简单理解成 “定义在一个函数内部的函数”。
      所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

      闭包就是一个函数引用另一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会增加内存消耗。

      闭包的用途:

      • 可以在函数外部读取函数内部成员
      • 让函数内成员始终存活在内存中
      function fn () {
        var count = 0
        return {
          getCount: function () {
            console.log(count)
          },
          setCount: function () {
            count++
          }
        }
      }
      
      var fns = fn()
      
      fns.getCount() // => 0
      fns.setCount()
      fns.getCount() // => 1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      作用域、作用域链、预解析
      • 全局作用域
      • 函数作用域
      • 没有块级作用域
      {
        var foo = 'bar'
      }
      
      console.log(foo)
      
      if (true) {
        var a = 123
      }
      console.log(a)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      作用域链示例代码:

      var a = 10
      
      function fn () {
        var b = 20
      
        function fn1 () {
          var c = 30
          console.log(a + b + c)
        }
      
        function fn2 () {
          var d = 40
          console.log(c + d)
        }
      
        fn1()
        fn2()
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 内层作用域可以访问外层作用域,反之不行
      一些关于闭包的例子

      示例1:

      var arr = [10, 20, 30]
      for(var i = 0; i < arr.length; i++) {
        arr[i] = function () {
          console.log(i)
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      示例2:

      console.log(111)
      
      for(var i = 0; i < 3; i++) {
        setTimeout(function () {
          console.log(i)
        }, 0)
      }
      console.log(222)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      闭包的思考题

      思考题 1:

      var name = "The Window";
      var object = {
        name: "My Object",
        getNameFunc: function () {
          return function () {
            return this.name;
          };
        }
      };
      
      console.log(object.getNameFunc()())//结果:The Window
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      思考题 2:

      var name = "The Window";  
      var object = {    
        name: "My Object",
        getNameFunc: function () {
          var that = this;
          return function () {
            return that.name;
          };
        }
      };
      console.log(object.getNameFunc()()) //结果:My Object
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      节流防抖

      js 函数的防抖(debounce)与节流(throttle) - shiweiqianju - 博客园 (cnblogs.com)

      jQuery

      js库

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEVfznDI-1646544115508)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209131529047.png)]

      jQuery对象和DOM对象

      jQuery对象只能使用jQuery方法,DOM对象只能使用原生的JavaScript属性和方法

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMCIN7Bz-1646544115509)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209131905694.png)]

      DOM对象转成jQuery对象

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JtF6Gh7R-1646544115509)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209132245006.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bg8wtNvx-1646544115509)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209132410004.png)]

      jQuery对象转成DOM对象

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rNaX3Rzn-1646544115510)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209132300951.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uQj25ZZU-1646544115510)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209132424531.png)]

      css()隐式迭代

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IT9NPCm1-1646544115510)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209134525226.png)]

      jQuery 尺寸方法

      jQuery 提供多个处理尺寸的重要方法:

      • width():设置或返回元素的宽度(不包括内边距、边框或外边距)
      • height():设置或返回元素的高度(不包括内边距、边框或外边距)
      • innerWidth():返回元素的宽度(包括内边距)
      • innerHeight():返回元素的高度(包括内边距
      • outerWidth():返回元素的宽度(包括内边距和边框)
      • outerWidth(true):返回元素的宽度(包括内边距,边框和外边距)
      • outerHeight(true):返回元素的高度(包括内边距,边框和外边距)
      事件

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yNjCEOTM-1646544115511)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209205953212.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUQsuYEI-1646544115511)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209205928089.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXC1wFs6-1646544115511)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209210534459.png)]

      浅拷贝和深拷贝

      JavaScript基础语法-dom-bom-js-es6新语法-jQuery-数据可视化echarts黑马pink老师前端入门基础视频教程(500多集)持续_哔哩哔哩_bilibili

      js浅拷贝与深拷贝的区别和实现方式 - 简书 (jianshu.com)

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dUacWul9-1646544115512)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209212741117.png)]

      如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。

      1. 如果是基本数据类型,名字和值都会储存在栈内存中
      var a = 1;
      b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的
      b = 2;
      console.log(a); // 1
      
      • 1
      • 2
      • 3
      • 4

      当然,这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

      2. 如果是引用数据类型,名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值
      比如浅拷贝:

      img

      image.png

      当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。

      img

      image.png

      而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。

      img

      image.png
      那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了

      img

      image.png

      3. 实现浅拷贝的方法

      (1)for···in只循环第一层

      // 只复制第一层的浅拷贝
      function simpleCopy(obj1) {
         var obj2 = Array.isArray(obj1) ? [] : {};
         for (let i in obj1) {
         obj2[i] = obj1[i];
        }
         return obj2;
      }
      var obj1 = {
         a: 1,
         b: 2,
         c: {
               d: 3
            }
      }
      var obj2 = simpleCopy(obj1);
      obj2.a = 3;
      obj2.c.d = 4;
      alert(obj1.a); // 1
      alert(obj2.a); // 3
      alert(obj1.c.d); // 4
      alert(obj2.c.d); // 4
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      (2)Object.assign方法

      var obj = {
          a: 1,
          b: 2
      }
      var obj1 = Object.assign(obj);
      obj1.a = 3;
      console.log(obj.a) // 3
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      (3)直接用=赋值

      let a=[0,1,2,3,4],
          b=a;
      console.log(a===b);
      a[0]=1;
      console.log(a,b);
      
      • 1
      • 2
      • 3
      • 4
      • 5

      img

      image.png

      4. 实现深拷贝的方法

      (1)采用递归去拷贝所有层级属性

      function deepClone(obj){
          let objClone = Array.isArray(obj)?[]:{};
          if(obj && typeof obj==="object"){
              for(key in obj){
                  if(obj.hasOwnProperty(key)){
                      //判断ojb子元素是否为对象,如果是,递归复制
                      if(obj[key]&&typeof obj[key] ==="object"){
                          objClone[key] = deepClone(obj[key]);
                      }else{
                          //如果不是,简单复制
                          objClone[key] = obj[key];
                      }
                  }
              }
          }
          return objClone;
      }    
      let a=[1,2,3,4],
          b=deepClone(a);
      a[0]=2;
      console.log(a,b);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

      结果:

      img

      image.png

      (2) 通过JSON对象来实现深拷贝

      function deepClone2(obj) {
        var _obj = JSON.stringify(obj),
          objClone = JSON.parse(_obj);
        return objClone;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

      缺点: 无法实现对对象中方法的深拷贝,会显示为undefined
      (3)通过jQuery的extend方法实现深拷贝

      var array = [1,2,3,4];
      var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
      
      • 1
      • 2

      (4)lodash函数库实现深拷贝

      let result = _.cloneDeep(test)
      
      • 1

      (5)Reflect法

      // 代理法
      function deepClone(obj) {
          if (!isObject(obj)) {
              throw new Error('obj 不是一个对象!')
          }
      
          let isArray = Array.isArray(obj)
          let cloneObj = isArray ? [...obj] : { ...obj }
          Reflect.ownKeys(cloneObj).forEach(key => {
              cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
          })
      
          return cloneObj
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      (6)手动实现深拷贝

      let obj1 = {
         a: 1,
         b: 2
      }
      let obj2 = {
         a: obj1.a,
         b: obj1.b
      }
      obj2.a = 3;
      alert(obj1.a); // 1
      alert(obj2.a); // 3
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      (7)如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象

      var obj = {
          a: 1,
          b: 2
      }
      var obj1 = Object.assign({}, obj); // obj赋值给一个空{}
      obj1.a = 3;
      console.log(obj.a);// 1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      img

      image.png

      (8)用slice实现对数组的深拷贝

      // 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
      // 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
      var arr1 = ["1","2","3"]; 
      var arr2 = arr1.slice(0);
      arr2[1] = "9";
      console.log("数组的原始值:" + arr1 );
      console.log("数组的新值:" + arr2 );
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      img

      image.png

      (9)用concat实现对数组的深拷贝

      // 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
      var arr1 = ["1","2","3"];
      var arr2 = arr1.concat();
      arr2[1] = "9";
      console.log("数组的原始值:" + arr1 );
      console.log("数组的新值:" + arr2 );
      // 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
      var arr1 = [{a:1},{b:2},{c:3}];
      var arr2 = arr1.concat();
      arr2[0].a = "9";
      console.log("数组的原始值:" + arr1[0].a ); // 数组的原始值:9
      console.log("数组的新值:" + arr2[0].a ); // 数组的新值:9
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      img

      image.png

      (10)直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

      function deepClone(initalObj, finalObj) {    
        var obj = finalObj || {};    
        for (var i in initalObj) {        
          var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
          if(prop === obj) {            
            continue;
          }        
          if (typeof prop === 'object') {
            obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
          } else {
            obj[i] = prop;
          }
        }    
        return obj;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      (11)使用扩展运算符实现深拷贝

      // 当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的
      // 当value是引用类型的值,比如Object,Array,引用类型进行深拷贝也只是拷贝了引用地址,所以属于浅拷贝
      var car = {brand: "BMW", price: "380000", length: "5米"}
      var car1 = { ...car, price: "500000" }
      console.log(car1); // { brand: "BMW", price: "500000", length: "5米" }
      console.log(car); // { brand: "BMW", price: "380000", length: "5米" }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      TypeScript

      强类型语言

      自行复习

      es6

      https://es6.ruanyifeng.com/

      1.1 ES6 教程 | 菜鸟教程 (runoob.com)

      1. let、const 和 block 作用域

      let 允许创建块级作用域,ES6 推荐在函数中使用 let 定义变量,而非 var:

      var a = 2;
      {
        let a = 3;
        console.log(a); // 3
      }
      console.log(a); // 2
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      {
        let a = 3;
        console.log(a); // 3
      }
      console.log(a); // 报错a is not defined
      
      • 1
      • 2
      • 3
      • 4
      • 5

      同样在块级作用域有效的另一个变量声明方式是 const,它可以声明一个常量。ES6 中,const 声明的常量类似于指针,它指向某个引用,也就是说这个「常量」并非一成不变的,如:

      {
        const ARR = [5,6];
        ARR.push(7);
        console.log(ARR); // [5,6,7]
        ARR = 10; // TypeError
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      有几个点需要注意:

      • let 关键词声明的变量不具备变量提升(hoisting)特性
      • let 和 const 声明只在最靠近的一个块中(花括号内)有效
      • 当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
      • const 在声明时必须被赋值
      • const 声明一个只读变量,声明之后不允许改变(对数组和对象的元素修改,不算做对常量的修改,不会报错)
      const array=[1,2,3];
      array.push(4);		//不会报错
      array=4		//报错
      
      • 1
      • 2
      • 3
      • let 只能声明一次 var 可以声明多次

      • 不影响作用域链

      • for (var i = 0; i < 10; i++) {
          setTimeout(function(){
            console.log(i);
          })
        }
        // 输出十个 10
        for (let j = 0; j < 10; j++) {
          setTimeout(function(){
            console.log(j);
          })
        }
        // 输出 0123456789
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12

      2. 箭头函数

      尚硅谷Web前端ES6教程,涵盖ES6-ES11_哔哩哔哩_bilibili

      ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体:

      var getPrice = function() {
        return 4.55;
      };
       
      // Implementation with Arrow Function
      var getPrice = () => 4.55;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      需要注意的是,上面例子中的 getPrice 箭头函数采用了简洁函数体,它不需要 return 语句,下面这个例子使用的是正常函数体:

      let arr = ['apple', 'banana', 'orange'];
       
      let breakfast = arr.map(fruit => {
        return fruit + 's';
      });
       
      console.log(breakfast); // apples bananas oranges
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      当然,箭头函数不仅仅是让代码变得简洁,函数中 this 总是绑定总是指向对象自身。具体可以看看下面几个例子:

      function Person() {
        this.age = 0;
       
        setInterval(function growUp() {
          // 在非严格模式下,growUp() 函数的 this 指向 window 对象
          this.age++;
        }, 1000);
      }
      var person = new Person();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      我们经常需要使用一个变量来保存 this,然后在 growUp 函数中引用:

      function Person() {
        var self = this;
        self.age = 0;
       
        setInterval(function growUp() {
          self.age++;
        }, 1000);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      而使用箭头函数可以省却这个麻烦:

      function Person(){
        this.age = 0;
       
        setInterval(() => {
          // |this| 指向 person 对象
          this.age++;
        }, 1000);
      }
       
      var person = new Person();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 箭头函数中的this是静态的,始终指向函数声明时所在作用域下的this的指向
      // 回调函数
      var Person = {
          'age': 18,
          'sayHello': function () {
            setTimeout(function () {
              console.log(this.age);		
            });
          }
      };
      var age = 20;
      Person.sayHello();  // 20	setTimeout=window.setTimeout,所以this指向window	
       
      var Person1 = {
          'age': 18,
          'sayHello': function () {
            setTimeout(()=>{
              console.log(this.age);
            });
              console.log(this);	//setTimeout里的this和此处的this均指向Person1
          }
      };
      var age = 20;
      Person1.sayHello();  // 18
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TAWhv43R-1646544115516)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210155736517.png)]

      function pp(){
      	console.log('p',this)		//this指向window
      }
      pp();
      
      • 1
      • 2
      • 3
      • 4

      3. 函数参数默认值

      从左向右依次赋值

      ES6 中允许你对函数参数设置默认值:

      let getFinalPrice = (price, tax=0.7) => price + price * tax;
      getFinalPrice(500); // 850
      
      • 1
      • 2

      4. Spread / Rest 操作符

      Spread / Rest 操作符指的是 …,具体是 Spread 还是 Rest 需要看上下文语境。

      必须放在最后一个参数

      正确:foo(x,y,z,…args)

      错误:foo(x,y,…args,z)

      当被用于迭代器中时,它是一个 Spread 操作符:

      function foo(x,y,z) {
        console.log(x,y,z);
      }
       
      let arr = [1,2,3];
      foo(...arr); // 1 2 3
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      当被用于函数传参时,是一个 Rest 操作符:

      function foo(...args) {
        console.log(args);
      }
      foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
      
      • 1
      • 2
      • 3
      • 4

      5. 对象词法扩展

      ES6 允许声明在对象字面量时使用简写语法,来初始化属性变量和函数的定义方法,并且允许在对象属性中进行计算操作:

      function getCar(make, model, value) {
        return {
          // 简写变量
          make,  // 等同于 make: make
          model, // 等同于 model: model
          value, // 等同于 value: value
       
          // 属性可以使用表达式计算值
          ['make' + make]: true,
       
          // 忽略 `function` 关键词简写对象函数
          depreciate() {
            this.value -= 2500;
          }
        };
      }
       
      let car = getCar('Barret', 'Lee', 40000);
       
      // output: {
      //     make: 'Barret',
      //     model:'Lee',
      //     value: 40000,
      //     makeBarret: true,
      //     depreciate: [Function: depreciate]
      // }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26

      6. 二进制和八进制字面量

      ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者0O 即可将其转换为八进制值:

      let oValue = 0o10;
      console.log(oValue); // 8
       
      let bValue = 0b10; // 二进制使用 `0b` 或者 `0B`
      console.log(bValue); // 2
      
      • 1
      • 2
      • 3
      • 4
      • 5

      7. 对象和数组解构

      拓展运算符

      拓展运算符(…)用于取出参数对象(也可用于数组)所有可遍历属性然后拷贝到当前对象。

      数组可以直接使用…array;对象只能在对象中使用{…obj}

      基本用法

      let person = {name: "Amy", age: 15}; let someone = { ...person }; someone;  //{name: "Amy", age: 15}
      
      • 1

      可用于合并两个对象

      let age = {age: 15}; let name = {name: "Amy"}; let person = {...age, ...name}; person;  //{age: 15, name: "Amy"}
      
      • 1

      注意点

      自定义的属性和拓展运算符对象里面属性的相同的时候:自定义的属性在拓展运算符后面,则拓展运算符对象内部同名的属性将被覆盖掉。

      let person = {name: "Amy", age: 15}; let someone = { ...person, name: "Mike", age: 17}; someone;  //{name: "Mike", age: 17}
      
      • 1

      自定义的属性在拓展运算度前面,则变成设置新对象默认属性值。

      let person = {name: "Amy", age: 15}; let someone = {name: "Mike", age: 17, ...person}; someone;  //{name: "Amy", age: 15}
      
      • 1

      拓展运算符后面是空对象,没有任何效果也不会报错。

      let a = {...{}, a: 1, b: 2}; a;  //{a: 1, b: 2}
      
      • 1

      拓展运算符后面是null或者undefined,没有效果也不会报错。

      let b = {...null, ...undefined, a: 1, b: 2}; b;  //{a: 1, b: 2}
      
      • 1
      数组模型的解构(Array)

      从左到右解构

      基本

      let [a, b, c] = [1, 2, 3]; // a = 1 // b = 2 // c = 3
      
      • 1

      可嵌套

      let [a, [[b], c]] = [1, [[2], 3]]; // a = 1 // b = 2 // c = 3
      
      • 1

      可忽略

      let [a, , b] = [1, 2, 3]; // a = 1 // b = 3
      
      • 1

      不完全解构

      let [a = 1, b] = []; // a = 1, b = undefined
      
      • 1

      剩余运算符

      let [a, ...b] = [1, 2, 3]; //a = 1 //b = [2, 3]
      
      • 1

      字符串等

      在数组的解构中,解构的目标若为可遍历对象,皆可进行解构赋值。可遍历对象即实现 Iterator 接口的数据。

      let [a, b, c, d, e] = 'hello'; // a = 'h' // b = 'e' // c = 'l' // d = 'l' // e = 'o'
      
      • 1

      解构默认值

      let [a = 2] = [undefined]; // a = 2
      
      • 1

      当解构模式有匹配结果,且匹配结果是 undefined 时,会触发默认值作为返回结果。

      let [a = 3, b = a] = [];     // a = 3, b = 3 
      let [a = 3, b = a] = [1];    // a = 1, b = 1 
      let [a = 3, b = a] = [1, 2]; // a = 1, b = 2
      
      • 1
      • 2
      • 3
      • a 与 b 匹配结果为 undefined ,触发默认值:a = 3; b = a =3
      • a 正常解构赋值,匹配结果:a = 1,b 匹配结果 undefined ,触发默认值:b = a =1
      • a 与 b 正常解构赋值,匹配结果:a = 1,b = 2

      对象模型的解构(Object)

      基本

      let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb' 
      let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd'
      
      • 1
      • 2

      可嵌套可忽略

      let obj = {p: ['hello', {y: 'world'}] };
      let {p: [x, { y }] } = obj; // x = 'hello' // y = 'world' 
      let obj = {p: ['hello', {y: 'world'}] };
      let {p: [x, {  }] } = obj; // x = 'hello'
      
      • 1
      • 2
      • 3
      • 4

      不完全解构

      let obj = {p: [{y: 'world'}] };
      let {p: [{ y }, x ] } = obj; // x = undefined // y = 'world'
      
      • 1
      • 2

      剩余运算符

      let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; // a = 10 // b = 20 // rest = {c: 30, d: 40}
      
      • 1

      解构默认值

      let {a = 10, b = 5} = {a: 3}; // a = 3; b = 5;
      let {a: aa = 10, b: bb = 5} = {a: 3}; // aa = 3; bb = 5;
      
      • 1
      • 2

      8. 对象超类

      ES6 允许在对象中使用 super 方法:

      var parent = {
        foo() {
          console.log("Hello from the Parent");
        }
      }
       
      var child = {
        foo() {
          super.foo();
          console.log("Hello from the Child");
        }
      }
       
      Object.setPrototypeOf(child, parent);
      child.foo(); // Hello from the Parent
                   // Hello from the Child
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      9. 模板语法和分隔符

      ES6 中有一种十分简洁的方法组装一堆字符串和变量。

      • ${ … } 用来渲染一个变量
      • ` 作为分隔符
      let user = 'Barret';
      console.log(`Hi ${user}!`); // Hi Barret!
      
      • 1
      • 2
      • 可以直接出现换行符

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J4Dcjr5y-1646544115517)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210153452156.png)]

      10. for…of VS for…in

      for…of 用于遍历一个迭代器,如数组:

      let nicknames = ['di', 'boo', 'punkeye'];
      nicknames.size = 3;
      for (let nickname of nicknames) {
        console.log(nickname);
      }
      // 结果: di, boo, punkeye
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      for…in 用来遍历对象中的属性:

      let nicknames = ['di', 'boo', 'punkeye'];
      nicknames.size = 3;
      for (let nickname in nicknames) {
        console.log(nickname);
      }
      Result: 0, 1, 2, size
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      11. Map 和 WeakMap

      Map 对象

      Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。

      Maps 和 Objects 的区别
      • 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
      • Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
      • Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
      • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

      img

      Map 中的 key

      key 是字符串

      var myMap = new Map();
      var keyString = "a string";  
      myMap.set(keyString, "和键'a string'关联的值"); 
      myMap.get(keyString);    // "和键'a string'关联的值"
      myMap.get("a string");   // "和键'a string'关联的值"                         // 因为 keyString === 'a string'
      
      • 1
      • 2
      • 3
      • 4
      • 5

      key 是对象

      var myMap = new Map();
      var keyObj = {},  
          myMap.set(keyObj, "和键 keyObj 关联的值"); 
      myMap.get(keyObj); // "和键 keyObj 关联的值"
      myMap.get({}); // undefined, 因为 keyObj !== {}
      
      • 1
      • 2
      • 3
      • 4
      • 5

      key 是函数

      var myMap = new Map(); 
      var keyFunc = function () {}, // 函数
          myMap.set(keyFunc, "和键 keyFunc 关联的值"); 
      myMap.get(keyFunc); // "和键 keyFunc 关联的值" 
      myMap.get(function() {}) // undefined, 因为 keyFunc !== function () {}
      
      • 1
      • 2
      • 3
      • 4
      • 5

      key 是 NaN

      var myMap = new Map(); 
      myMap.set(NaN, "not a number");  
      
      myMap.get(NaN); // "not a number" 
      
      var otherNaN = Number("foo"); 
      myMap.get(otherNaN); // "not a number"
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      虽然 NaN 和任何值甚至和自己都不相等(NaN !== NaN 返回true),NaN作为Map的键来说是没有区别的。

      Map 的迭代

      对 Map 进行遍历,以下两个最高级。

      for…of
      var myMap = new Map();
      myMap.set(0, "zero");
      myMap.set(1, "one");  
      // 将会显示两个 log。 一个是 "0 = zero" 另一个是 "1 = one"
      for (var [key, value] of myMap) {  
          console.log(key + " = " + value); 
      }
      for (var [key, value] of myMap.entries()) { 
          console.log(key + " = " + value); 
      }
      /* 这个 entries 方法返回一个新的 Iterator 对象,它按插入顺序包含了 Map 对象中每个元素的 [key, value] 数组。 */
      // 将会显示两个log。 一个是 "0" 另一个是 "1"
      for (var key of myMap.keys()) { 
          console.log(key);
      } 
      /* 这个 keys 方法返回一个新的 Iterator 对象, 它按插入顺序包含了 Map 对象中每个元素的键。 */ 
      // 将会显示两个log。 一个是 "zero" 另一个是 "one"
      for (var value of myMap.values()) {  
          console.log(value);
      } 
      /* 这个 values 方法返回一个新的 Iterator 对象,它按插入顺序包含了 Map 对象中每个元素的值。 */
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      forEach()
      var myMap = new Map();
      myMap.set(0, "zero"); 
      myMap.set(1, "one");  
      // 将会显示两个 logs。 一个是 "0 = zero" 另一个是 "1 = one" 
      myMap.forEach(function(value, key) {  
          console.log(key + " = " + value);
      }, myMap)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      Map 对象的操作

      Map 与 Array的转换

      var kvArray = [["key1", "value1"], ["key2", "value2"]];  
      // Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象 
      var myMap = new Map(kvArray); 
      
      // 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
      var outArray = Array.from(myMap);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      Map 的克隆

      var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]); 
      var myMap2 = new Map(myMap1);  
      
      console.log(original === clone); 
      // 打印 false。 Map 对象构造函数生成实例,迭代出新的对象。
      
      • 1
      • 2
      • 3
      • 4
      • 5

      Map 的合并

      var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);
      var second = new Map([[1, 'uno'], [2, 'dos']]);  
      // 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的,对应值即 uno,dos, three
      var merged = new Map([...first, ...second]);
      
      • 1
      • 2
      • 3
      • 4
      WeakMap

      WeakMap 就是一个 Map,只不过它的所有 key 都是弱引用,意思就是 WeakMap 中的东西垃圾回收时不考虑,使用它不用担心内存泄漏问题。

      另一个需要注意的点是,WeakMap 的所有 key 必须是对象。它只有四个方法 delete(key),has(key),get(key) 和set(key, val):

      let w = new WeakMap();
      w.set('a', 'b'); 
      // Uncaught TypeError: Invalid value used as weak map key
       
      var o1 = {},
          o2 = function(){},
          o3 = window;
       
      w.set(o1, 37);
      w.set(o2, "azerty");
      w.set(o3, undefined);
       
      w.get(o3); // undefined, because that is the set value
       
      w.has(o1); // true
      w.delete(o1);
      w.has(o1); // false
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      12. Set 和 WeakSet

      Set 对象

      Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。

      Set 中的特殊值

      Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待:

      • +0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复;
      • undefined 与 undefined 是恒等的,所以不重复;
      • NaN 与 NaN 是不恒等的,但是在 Set 中只能存一个,不重复。

      代码

      let mySet = new Set();  
      ySet.add(1); // Set(1) {1}
      mySet.add(5); // Set(2) {1, 5} 
      mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性 
      mySet.add("some text"); 
      // Set(3) {1, 5, "some text"} 这里体现了类型的多样性 
      var o = {a: 1, b: 2}; 
      mySet.add(o); 
      mySet.add({a: 1, b: 2}); 
      // Set(5) {1, 5, "some text", {…}, {…}}  
      // 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      类型转换

      Array

      // Array 转 Set 
      var mySet = new Set(["value1", "value2", "value3"]);
      // 用...操作符,将 Set 转 Array 
      var myArray = [...mySet]; 
      String
      // String 转 Set 
      var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
      // 注:Set 中 toString 方法是不能将 Set 转换成 String
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      Set 对象作用

      数组去重

      var mySet = new Set([1, 2, 3, 4, 4]);
      [...mySet]; // [1, 2, 3, 4]
      
      • 1
      • 2

      并集

      var a = new Set([1, 2, 3]);
      var b = new Set([4, 3, 2]);
      var union = new Set([...a, ...b]); // {1, 2, 3, 4}
      
      • 1
      • 2
      • 3

      交集

      var a = new Set([1, 2, 3]);
      var b = new Set([4, 3, 2]); 
      var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
      
      • 1
      • 2
      • 3

      差集

      var a = new Set([1, 2, 3]); 
      var b = new Set([4, 3, 2]);
      var difference = new Set([...a].filter(x => !b.has(x))); // {1}
      
      • 1
      • 2
      • 3
      WeakSet

      类似于 WeakMap,WeakSet 对象可以让你在一个集合中保存对象的弱引用,在 WeakSet 中的对象只允许出现一次:

      var ws = new WeakSet();
      var obj = {};
      var foo = {};
       
      ws.add(window);
      ws.add(obj);
       
      ws.has(window); // true
      ws.has(foo);    // false, foo 没有添加成功
       
      ws.delete(window); // 从结合中删除 window 对象
      ws.has(window);    // false, window 对象已经被删除
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      13. 类

      ES6 中有 class 语法。值得注意是,这里的 class 不是新的对象继承模型,它只是原型链的语法糖表现形式。

      函数中使用 static 关键词定义构造函数的的方法和属性:

      class Task {
        constructor() {
          console.log("task instantiated!");
        }
       
        showId() {
          console.log(23);
        }
       
        static loadAll() {
          console.log("Loading all tasks..");
        }
      }
       
      console.log(typeof Task); // function
      let task = new Task(); // "task instantiated!"
      task.showId(); // 23
      Task.loadAll(); // "Loading all tasks.."
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      类中的继承和超集:

      class Car {
        constructor() {
          console.log("Creating a new car");
        }
      }
       
      class Porsche extends Car {
        constructor() {
          super();
          console.log("Creating Porsche");
        }
      }
       
      let c = new Porsche();
      // Creating a new car
      // Creating Porsche
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      extends 允许一个子类继承父类,需要注意的是,子类的constructor 函数中需要执行 super() 函数。

      当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()。

      在 这里 阅读更多关于类的介绍。

      有几点值得注意的是:

      • 类的声明不会提升(hoisting),如果你要使用某个 Class,那你必须在使用之前定义它,否则会抛出一个 ReferenceError 的错误
      • 在类中定义函数不需要使用 function 关键词

      14. Symbol

      Symbol 是一种新的数据类型,它的值是唯一的,不可变的。ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符:

      var sym = Symbol( "some optional description" );
      console.log(typeof sym); // symbol
      
      • 1
      • 2

      注意,这里 Symbol 前面不能使用 new 操作符。

      如果它被用作一个对象的属性,那么这个属性会是不可枚举的:

      var o = {
          val: 10,
          [ Symbol("random") ]: "I'm a symbol",
      };
       
      console.log(Object.getOwnPropertyNames(o)); // val
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      如果要获取对象 symbol 属性,需要使用Object.getOwnPropertySymbols(o)。

      通过Symbol.for()创建时可以相同

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5aBQ6BJm-1646544115518)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210165150608.png)]

      如上面的s2和s3不相等,s4和s5相等

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EKsKsfyx-1646544115518)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210164802368.png)]

      作为属性名

      用法

      由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。

      let sy = Symbol(“key1”); // 写法1 let syObject = {}; syObject[sy] = “kk”; console.log(syObject); // {Symbol(key1): “kk”} // 写法2 let syObject = { [sy]: “kk” }; console.log(syObject); // {Symbol(key1): “kk”} // 写法3 let syObject = {}; Object.defineProperty(syObject, sy, {value: “kk”}); console.log(syObject); // {Symbol(key1): “kk”}

      Symbol 作为对象属性名时不能用.运算符,要用方括号。因为.运算符后面是字符串,所以取到的是字符串 sy 属性,而不是 Symbol 值 sy 属性。

      let syObject = {}; syObject[sy] = “kk”; syObject[sy]; // “kk” syObject.sy; // undefined

      15. 迭代器(Iterators)

      迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素时,迭代器便会退出。它提供了 next() 函数来遍历一个序列,这个方法返回一个包含 done 和 value 属性的对象。

      ES6 中可以通过 Symbol.iterator 给对象设置默认的遍历器,无论什么时候对象需要被遍历,执行它的 @@iterator 方法便可以返回一个用于获取值的迭代器。

      数组默认就是一个迭代器:

      var arr = [11,12,13];
      var itr = arr[Symbol.iterator]();
       
      itr.next(); // { value: 11, done: false }
      itr.next(); // { value: 12, done: false }
      itr.next(); // { value: 13, done: false }
       
      itr.next(); // { value: undefined, done: true }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      你可以通过 Symbol.iterator 自定义一个对象的迭代器。

      var arr = ['a', 'b', 'c', 'd'];
      
      for (let a in arr) {
        console.log(a); // 0 1 2 3
      }
      
      for (let a of arr) {
        console.log(a); // a b c d
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      上面代码表明,for...in循环读取键名,for...of循环读取键值。如果要通过for...of循环,获取数组的索引,可以借助数组实例的entries方法和keys方法(参见《数组的扩展》一章)。

      对于普通的对象,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。但是,这样情况下,for...in循环依然可以用来遍历键名。

      一种解决方法是,使用Object.keys方法将对象的键名生成一个数组,然后遍历这个数组。

      for (var key of Object.keys(someObject)) {
        console.log(key + ': ' + someObject[key]);
      }
      
      • 1
      • 2
      • 3

      另一个方法是使用 Generator 函数将对象重新包装一下。

      const obj = { a: 1, b: 2, c: 3 }
      
      function* entries(obj) {
        for (let key of Object.keys(obj)) {
          yield [key, obj[key]];
        }
      }
      
      for (let [key, value] of entries(obj)) {
        console.log(key, '->', value);
      }
      // a -> 1
      // b -> 2
      // c -> 3
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      也可以手动写Symbom.iterator方法

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QIr1oSw9-1646544115519)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210174944934.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Px0ZPg6s-1646544115519)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210174926840.png)]

      16. Generators

      Generator 函数组成

      Generator 有两个区分于普通函数的部分:

      • 一是在 function 后面,函数名之前有个 * ;
      • 函数内部有 yield 表达式。

      其中 * 用来表示函数为 Generator 函数,yield 用来定义函数内部的状态。

      function* func(){
          console.log("one");
          yield '1'; 
          console.log("two"); 
          yield '2';
          console.log("three");
          return '3';
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      执行机制

      调用 Generator 函数和调用普通函数一样,在函数名后面加上()即可,但是 Generator 函数不会像普通函数一样立即执行,而是返回一个指向内部状态对象的指针,所以要调用遍历器对象Iterator 的 next 方法,指针就会从函数头部或者上一次停下来的地方开始执行。

      f.next();
      // one
      // {value: "1", done: false}  
      f.next();
      // two
      // {value: "2", done: false} 
      f.next();
      // three
      // {value: "3", done: true} 
      f.next(); 
      // {value: undefined, done: true}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      第一次调用 next 方法时,从 Generator 函数的头部开始执行,先是打印了 one ,执行到 yield 就停下来,并将yield 后边表达式的值 ‘1’,作为返回对象的 value 属性值,此时函数还没有执行完, 返回对象的 done 属性值是 false。

      第二次调用 next 方法时,同上步 。

      第三次调用 next 方法时,先是打印了 three ,然后执行了函数的返回操作,并将 return 后面的表达式的值,作为返回对象的 value 属性值,此时函数已经结束,多以 done 属性值为true 。

      第四次调用 next 方法时, 此时函数已经执行完了,所以返回 value 属性值是 undefined ,done 属性值是 true 。如果执行第三步时,没有 return 语句的话,就直接返回 {value: undefined, done: true}。

      函数返回的遍历器对象的方法

      next 方法

      一般情况下,next 方法不传入参数的时候,yield 表达式的返回值是 undefined 。当 next 传入参数的时候,该参数会作为上一步yield的返回值。

      function* sendParameter(){  
          console.log("start");  
          var x = yield '2';  
          console.log("one:" + x); 
          var y = yield '3';   
          console.log("two:" + y); 
          console.log("total:" + (x + y)); 
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      next不传参

      var sendp1 = sendParameter();
      sendp1.next(); 
      // start 
      // {value: "2", done: false}
      sendp1.next(); 
      // one:undefined 
      // {value: "3", done: false}
      sendp1.next(); 
      // two:undefined 
      // total:NaN 
      // {value: undefined, done: true} 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      next传参

      var sendp2 = sendParameter(); 
      sendp2.next(10); 
      // start
      // {value: "2", done: false} 
      sendp2.next(20); 
      // one:20 
      // {value: "3", done: false}
      sendp2.next(30); 
      // two:30 
      // total:50 
      // {value: undefined, done: true}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      除了使用 next ,还可以使用 for… of 循环遍历 Generator 函数生产的 Iterator 对象。

      return 方法

      return 方法返回给定值,并结束遍历 Generator 函数。

      return 方法提供参数时,返回该参数;不提供参数时,返回 undefined 。

      function* foo(){   
          yield 1;   
          yield 2;    
          yield 3;
      } 
      var f = foo();
      f.next(); 
      // {value: 1, done: false} 
      f.return("foo"); 
      // {value: "foo", done: true} 
      f.next();
      // {value: undefined, done: true} 
      throw 方法 
      throw 方法可以再 Generator 函数体外面抛出异常,再函数体内部捕获。 
      var g = function* () {  
          try {    
              yield;  
          } catch (e) { 
              console.log('catch inner', e);  
          } 
      };  
      var i = g();
      i.next(); 
      try { 
          i.throw('a');
          i.throw('b');
      } catch (e) { 
          console.log('catch outside', e);
      } 
      // catch inner a 
      // catch outside b
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31

      遍历器对象抛出了两个错误,第一个被 Generator 函数内部捕获,第二个因为函数体内部的catch 函数已经执行过了,不会再捕获这个错误,所以这个错误就抛出 Generator 函数体,被函数体外的 catch 捕获。

      yield* 表达式

      yield* 表达式表示 yield 返回一个遍历器对象,用于在 Generator 函数内部,调用另一个 Generator 函数。

      function* callee() {   
          console.log('callee: ' + (yield));
      }
      function* caller() {
          while (true) {   
              yield* callee();  
          } 
      }
      const callerObj = caller(); 
      callerObj.next();
      // {value: undefined, done: false} 
      callerObj.next("a"); 
      // callee: a 
      // {value: undefined, done: false} 
      callerObj.next("b");
      // callee: b 
      // {value: undefined, done: false}  
      // 等同于
      function* caller() {  
          while (true) {   
              for (var value of callee) {  
                  yield value;      
              }   
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25

      17. Promises

      ES6 对 Promise 有了原生的支持,一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者rejected。

      var p = new Promise(function(resolve, reject) {  
        if (/* condition */) {
          // fulfilled successfully
          resolve(/* value */);  
        } else {
          // error, rejected
          reject(/* reason */);  
        }
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      每一个 Promise 都有一个 .then 方法,这个方法接受两个参数,第一个是处理 resolved 状态的回调,一个是处理 rejected 状态的回调:

      p.then((val) => console.log("Promise Resolved", val),
             (err) => console.log("Promise Rejected", err));
      
      • 1
      • 2

      axios

      自己学习

      webpack

      概念

      webpack是前端项目工程化的具体解决方案。
      主要功能:它提供了友好的前端模块化开发支持,以及代码压缩混淆、处理浏览器端JavaScript的兼容性、性能优化等强大的功能。

      vue

      组件化和模块化

      组件化:

      ​ 1: 就是"基础库"或者"基础组件", 意思就是把重复的代码部分提炼出一个个组件供给功能使用

        2: 功能相对单一或者独立, 在整个系统的代码层次上位于最底层,被其他代码所依赖,所以说组件化是纵向分层。
      
       3: 使用场景: 是对一些重复代码进行封装在需要的时候调用即可(例如: 按钮, 输入框, 搜索框)
      
       4:  目得: 复用, 解耦
      
      • 1
      • 2
      • 3
      • 4
      • 5
      模块化

      ​ 1: 就是"业务框架"或者"业务模块", 将不同的业务进行划分, 同一类型的整合在一起, 所以功能会相对复杂, 但是都属于同一个业务

          2: 按照项目功能需求划分成不同类型的业务框架(例如:注册、登录、外卖、直播.....)
      
          3: 目得:  隔离.分装, 模块之间有依赖的关系, 可以通过路由进行模块直接的耦合问题
      
      • 1
      • 2
      • 3
      区别

      组件:就像一个个小的单位,多个组件可以组合成组件库,方便调用和复用,组件间也可以嵌套,小组件组合成大组件。

      模块:就像是独立的功能和项目(如淘宝:注册、登录、购物、直播…),可以调用组件来组成模块,多个模块可以组合成业务框架。

      使用组件化和模块化的好处 :
      开发和调试效率高:随着功能越来越多,代码结构会越发复杂,要修改某一个小功能,可能要重新翻阅整个项目的代码,把所有相同的地方都修改一遍,重复劳动浪费时间和人力,效率低;使用组件化,每个相同的功能结构都调用同一个组件,只需要修改这个组件,即可全局修改。

      可维护性强:便于后期代码查找和维护。

      避免阻断:模块化是可以独立运行的,如果一个模块产生了bug,不会影响其他模块的调用。

      版本管理更容易:如果由多人协作开发,可以避免代码覆盖和冲突。

      什么是 vue

      1. 构建用户界面
        • 用 vue 往 html 页面中填充数据,非常的方便
      2. 框架
        • 框架是一套现成的解决方案,程序员只能遵守框架的规范,去编写自己的业务功能!
        • 要学习 vue,就是在学习 vue 框架中规定的用法!
        • vue 的指令、组件(是对 UI 结构的复用)、路由、Vuex、vue 组件库
        • 只有把上面老师罗列的内容掌握以后,才有开发 vue 项目的能力!

      vue 的两个特性

      1. 数据驱动视图:

        • 数据的变化会驱动视图自动更新
        • 好处:程序员只管把数据维护好,那么页面结构会被 vue 自动渲染出来!
      2. 双向数据绑定:

        在网页中,form 表单负责采集数据,Ajax 负责提交数据

        • js 数据的变化,会被自动渲染到页面上
        • 页面上表单采集的数据发生变化的时候,会被 vue 自动获取到,并更新到 js 数据中

      注意:数据驱动视图和双向数据绑定的底层原理是 MVVM(Mode 数据源、View 视图、ViewModel 就是 vue 的实例)

      vue 指令

      1. 内容渲染指令
      1. v-text 指令的缺点:会覆盖元素内部原有的内容!
      2. {{ }} 插值表达式:在实际开发中用的最多,只是内容的占位符,不会覆盖原有的内容!
      3. v-html 指令的作用:可以把带有标签的字符串,渲染成真正的 HTML 内容!
      2. 属性绑定指令

      注意:插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中!

      • 在 vue 中,可以使用 v-bind: 指令,为元素的属性动态绑定值;

      • 简写是英文的 :

      • 在使用 v-bind 属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,例如:

        <div :title="'box' + index">这是一个 div</div>
        
        • 1
      3. 事件绑定
      1. v-on: 简写是 @

      2. 语法格式为:

        <button @click="add"></button>
        
        methods: {
           add() {
        			// 如果在方法中要修改 data 中的数据,可以通过 this 访问到
        			this.count += 1
           }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
      3. $event 的应用场景:如果默认的事件对象 e 被覆盖了,则可以手动传递一个 $event。例如:

        <button @click="add(3, $event)"></button>
        
        methods: {
           add(n, e) {
        			// 如果在方法中要修改 data 中的数据,可以通过 this 访问到
        			this.count += 1
           }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

        也可以不传递直接在函数中使用event

      4. 事件修饰符:

        • .prevent

          <a @click.prevent="xxx">链接</a>
          
          • 1
        • .stop

          <button @click.stop="xxx">按钮</button>
          
          • 1
      4. v-model 指令
      1. input 输入框
        • type=“radio”
        • type=“checkbox”
        • type=“xxxx”
      2. textarea
      3. select
      5. 条件渲染指令
      1. v-show 的原理是:动态为元素添加或移除 display: none 样式,来实现元素的显示和隐藏
        • 如果要频繁的切换元素的显示状态,用 v-show 性能会更好
      2. v-if 的原理是:每次动态创建或移除元素,实现元素的显示和隐藏
        • 如果刚进入页面的时候,某些元素默认不需要被展示,而且后期这个元素很可能也不需要被展示出来,此时 v-if 性能更好

      在实际开发中,绝大多数情况,不用考虑性能问题,直接使用 v-if 就好了!!!

      v-if 指令在使用的时候,有两种方式:

      1. 直接给定一个布尔值 true 或 false

        <p v-if="true">被 v-if 控制的元素</p>
        
        • 1
      2. 给 v-if 提供一个判断条件,根据判断的结果是 true 或 false,来控制元素的显示和隐藏

        <p v-if="type === 'A'">良好</p>
        
        • 1

      vue生命周期

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KoHTE0H-1646544115520)(E:\BaiduNetdiskDownload\day4\讲义\lifecycle.png)]

      beforeCreate( 创建前 )

      在实例化之后,数据的观测和事件的配置之前的时候调用,此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据

      created ( 创建后)

      在创建之后使用,主要用于数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。 然而,挂在阶段还没有开始.

      beforeMount (挂载前)

      用于在挂载之前使用,在这个阶段是获取不到dom操作的,把data里面的数据和模板生成html,完成了data等初始化,注意此时还没有挂在html到页面上

      mount (挂载后)

      用于挂载之后使用,在这个时候可以获取到dom操作,比如可以获取到ref等,操作的dom, 在这个时候只能调用一次ajax,在这个时候el和data都可以获取的到

      beforeUpdate (更新前)

      在数据更新之前被调用,发生在虚拟DOM重新渲染,可以在该钩子中进一步地更改状态,不会触发重复渲染过程

      updated (更新后)

      在由于数据更改导致地虚拟DOM重新渲染会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,但是在服务器端渲染期间不被调用,可以用于监听某些数据的时候使用钩子

      beforeDestroy(销毁前)

      在这个时候还是可以用this来获取,可以用于销毁计时器时候使用,为了防止跳转到其它页面该事件还在执行,还可以清除dom事件等

      destroy(销毁后)

      在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁.

      过滤器

      过滤器的注意点
      1. 要定义到 filters 节点下,本质是一个函数
      2. 在过滤器函数中,一定要有 return 值
      3. 在过滤器的形参中,可以获取到“管道符”前面待处理的那个值
      4. 如果全局过滤器和私有过滤器名字一致,此时按照“就近原则”,调用的是”私有过滤器“

      watch 侦听器

      侦听器的格式
      1. 方法格式的侦听器
        • 缺点1:无法在刚进入页面的时候,自动触发!!!
        • 缺点2:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器!!!
      2. 对象格式的侦听器
        • 好处1:可以通过 immediate 选项,让侦听器自动触发!!!
        • 好处2:可以通过 deep 选项,让侦听器深度监听对象中每个属性的变化!!!

      计算属性

      特点:

      1. 定义的时候,要被定义为“方法”
      2. 在使用计算属性的时候,当普通的属性使用即可

      好处:

      1. 实现了代码的复用
      2. 只要计算属性中依赖的数据源变化了,则计算属性会自动重新求值!

      axios

      axios 是一个专注于网络请求的库!

      axios 的基本使用
      1. 发起 GET 请求:

        axios({
          // 请求方式
          method: 'GET',
          // 请求的地址
          url: 'http://www.liulongbin.top:3006/api/getbooks',
          // URL 中的查询参数
          params: {
            id: 1
          }
        }).then(function (result) {
          console.log(result)
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
      2. 发起 POST 请求:

        document.querySelector('#btnPost').addEventListener('click', async function () {
          // 如果调用某个方法的返回值是 Promise 实例,则前面可以添加 await!
          // await 只能用在被 async “修饰”的方法中
          const { data: res } = await axios({
            method: 'POST', 
            url: 'http://www.liulongbin.top:3006/api/post',
            data: {
              name: 'zs',
              age: 20
            }
          })
        
          console.log(res)
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14

      vue-cli 的使用

      1. 在终端下运行如下的命令,创建指定名称的项目:

        vue cerate 项目的名称
        
        • 1
      2. vue 项目中 src 目录的构成:

        assets 文件夹:存放项目中用到的静态资源文件,例如:css 样式表、图片资源
        components 文件夹:程序员封装的、可复用的组件,都要放到 components 目录下
        main.js 是项目的入口文件。整个项目的运行,要先执行 main.js
        App.vue 是项目的根组件。
        
        • 1
        • 2
        • 3
        • 4

      react

      自行学习

      php

      自行学习

      laraval

      mysql

      自行学习

      声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
      推荐阅读
        

      闽ICP备14008679号