赞
踩
超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。(是标记语言,不是编程语言)
主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
JS引擎则:解析和执行javascript来实现网页的动态效果。
最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称MSHTML]
Gecko内核:Netscape6及以上版本,FireFox,MozillaSuite/SeaMonkey等
Presto内核:Opera7及以上。 [Opera内核原为:Presto,现为:Blink;]
Webkit内核:Safari,Chrome等。 [ Chrome的:Blink(WebKit的分支)]
详细文章:浏览器内核的解析和对比
前缀 | 浏览器 | 例 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 |
标准 | 说明 | 备注 |
---|---|---|
结构 | 结构用于对网页元素进行整理和分类,主要是HTML。 | |
表现 | 表现用于设置网页元素的版式、颜色、大小等外观样式,主要指的是CSS | |
行为 | 行为是指网页模型的定义及交互的编写,主要是 Javascript |
理想状态我们的源码: .HTML .css .js
声明为 HTML5 文档,doctype 声明是不区分大小写的
元素是 HTML 页面的根元素
元素包含了文档的元(meta)数据,如 定义网页编码格式为 utf-8。
元素包含了可见的页面内容
元素定义一个段落
lang:en 、zh-CN、 fr
查看完整网页声明类型 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 图形的容器。 |
标签 | 描述 |
---|---|
定义声音内容。 | |
定义媒介源。 | |
定义用在媒体播放器中的文本轨道。 | |
定义视频。 |
标签 | 描述 |
---|---|
| 定义无序列表。 |
| 定义有序列表。 |
定义列表的项目。 | |
| 定义大号文本。HTML5 中不支持。请使用 CSS 代替。 |
| 定义定义列表。 |
定义定义列表中的项目。 | |
定义定义列表中项目的描述。 | |
定义命令的菜单/列表。 | |
定义用户可以从弹出菜单调用的命令/菜单项目。 | |
定义命令按钮。 |
标签 | 描述 | |
---|---|---|
| 定义表格 | |
定义表格标题。 | ||
定义表格中的表头单元格。 | ||
定义表格中的行。 | ||
定义表格中的单元。 | ||
定义表格中的表头内容。 | ||
定义表格中的主体内容。 | ||
定义表格中的表注内容(脚注)。 | ||
定义表格中一个或多个列的属性值。 | ||
定义表格中供格式化的列组。 |
标签 | 描述 |
---|---|
标签 | 描述 |
---|---|
定义关于文档的信息。 | |
定义关于 HTML 文档的元信息。 | |
定义页面中所有链接的默认地址或默认目标。 | |
定义页面中文本的默认字体、颜色或尺寸。HTML5 中不支持。请使用 CSS 代替。 |
标签 | 描述 |
---|---|
如空格等等
HTML ISO-8859-1 参考手册 | 菜鸟教程 (runoob.com)
HTML 符号实体参考手册 | 菜鸟教程 (runoob.com)
字符 | 实体编号 | 实体名称 | 描述 |
---|---|---|---|
> | > | ||
< | < | ||
  |   | 非间断空格(non-breaking space) |
<!doctype> 声明必须位于 HTML5 文档中的第一行,使用非常简单:
<!DOCTYPE html>
HTML5 中的一些有趣的新特性:
- <acronym>
- <applet>
- <basefont>
- <big>
- <center>
- <dir>
- <font>
- <frame>
- <frameset>
- <noframes>
- <strike>
- <tt>
标签 | 描述 |
---|---|
标签定义图形,比如图表和其他图像。该标签基于 JavaScript 的绘图 API |
标签 | 描述 |
---|---|
定义音频内容 | |
定义视频(video 或者 movie) | |
定义多媒体资源 和 | |
定义嵌入的内容,比如插件。 | |
为诸如 和 元素之类的媒介规定外部文本轨道。 |
标签 | 描述 |
---|---|
定义选项列表。请与 input 元素配合使用该元素,来定义 input 可能的值。 | |
规定用于表单的密钥对生成器字段。 | |
定义不同类型的输出,比如脚本的输出。 |
HTML5提供了新的元素来创建更好的页面结构:
标签 | 描述 |
---|---|
定义页面独立的内容区域。 | |
定义页面的侧边栏内容。 | |
允许您设置一段文本,使其脱离其父元素的文本方向设置。 | |
定义命令按钮,比如单选按钮、复选框或按钮 | |
用于描述文档或文档某个部分的细节 | |
定义对话框,比如提示框 | |
标签包含 details 元素的标题 | |
规定独立的流内容(图像、图表、照片、代码等等)。 | |
| 定义 |
定义 section 或 document 的页脚。 | |
| 定义了文档的头部区域 |
定义带有记号的文本。 | |
定义度量衡。仅用于已知最大和最小值的度量。 | |
定义导航链接的部分。 | |
定义任何类型的任务的进度。 | |
定义 ruby 注释(中文注音或字符)。 | |
定义字符(中文注音或字符)的解释或发音。 | |
在 ruby 注释中使用,定义不支持 ruby 元素的浏览器所显示的内容。 | |
定义文档中的节(section、区段)。 | |
定义日期或时间。 | |
规定在文本中的何处适合添加换行符。 |
以下的 HTML 4.01 元素在HTML5中已经被删除:
选取某元素的后代元素。div p { background-color:yellow; }
与后代选择器相比,子元素选择器(Child selectors)只能选择作为某元素直接/一级子元素的元素。div>p { background-color:yellow; }
div,p { background-color:yellow; }
这四个按照顺序:link :visited :hover :active声明
n可以为数字;n也可以为关键字:even-偶数,odd-奇数;n也可以为公式如n,2n,2n+1,n从0开始
选择器 | 示例 | 示例说明 |
---|---|---|
:checked | input:checked | 选择所有选中的表单元素 |
:disabled | input:disabled | 选择所有禁用的表单元素 |
:empty | p:empty | 选择所有没有子元素的p元素 |
:enabled | input:enabled | 选择所有启用的表单元素 |
:first-of-type | p:first-of-type | 选择的每个 p 元素是其父元素的第一个 p 元素 |
:in-range | input:in-range | 选择元素指定范围内的值 |
:invalid | input:invalid | 选择所有无效的元素 |
:last-child | p:last-child | 选择所有p元素的最后一个子元素 |
:last-of-type | p: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-type | p:only-of-type | 选择所有仅有一个子元素为p的元素 |
:only-child | p:only-child | 选择所有仅有一个子元素的p元素 |
:optional | input:optional | 选择没有"required"的元素属性 |
:out-of-range | input:out-of-range | 选择指定范围以外的值的元素属性 |
:read-only | input:read-only | 选择只读属性的元素属性 |
:read-write | input:read-write | 选择没有只读属性的元素属性 |
:required | input:required | 选择有"required"属性指定的元素属性 |
:root | root | 选择文档的根元素 |
:target | #news:target | 选择当前活动#news元素(点击URL包含锚的名字) |
:valid | input:valid | 选择所有有效值的属性 |
:link | a:link | 选择所有未访问链接 |
:visited | a:visited | 选择所有访问过的链接 |
:active | a:active | 选择正在活动链接 |
:hover | a:hover | 把鼠标放在链接上的状态 |
:focus | input:focus | 选择元素输入后具有焦点 |
:first-letter | p:first-letter | 选择每个 元素的第一个字母 |
:first-line | p:first-line | 选择每个 元素的第一行 |
:first-child | p:first-child | 选择器匹配属于任意元素的第一个子元素的 元素 |
:before | p:before | 在每个 元素之前插入内容,::before也对 |
:after | p:after | 在每个 元素之后插入内容,::after也对 |
:lang(language) | p:lang(it) | 为 元素的lang属性选择一个开始值 |
.img:hover:before{
}
下面的例子是把包含属性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>
下面是包含指定值的lang属性的元素样式的例子,使用(|)分隔属性和值:
[lang|=en] { color:blue; }
px:像素单位
rpx:小程序端常用,1px=2rpx,1rpx=1物理像素
em:当前元素(font-size)1个文字的大小
内部样式表
行内样式表style=""
外部样式表
display属性设置
div ul ol li dl dt dd h1 h2 h3 h4…p
p和h标签内部不能放其他块级元素
自己独占一行(设置宽高后也是)
a b span img input select strong
行内元素的宽高直接设置时无效
行内元素只能容纳文本或其他行内元素
里面不能放,特殊情况里面可以放块级元素
和其他行内或行内块级元素元素放置在同一行上; 元素的高度、宽度、行高以及顶 和底边距都可设置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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;
}
<style>
div{color:pink;font-size:20px;}
</style>
<div>
<span>
我是什么颜色的?
</span>
</div>
在复杂CSS样式表,往往并不是相同样式不同值的堆叠这么简单,经常出现两个或多个不同样式规则应用在同一元素上,这时到底采用哪个样式呢?这就是典型的CSS优先级问题。
处理优先级问题,就是考虑样式权重的高低。这里先给大家介绍一些特殊的情况:
行内元素可以设置左右margin
margin-left:auto 可以使元素居中
行内元素可以设置padding,但无法撑开盒子
重要: 当您指定一个 CSS 元素的宽度和高度属性时,你只是设置内容区域的宽度和高度。要知道,完整大小的元素,你还必须添加内边距,边框和外边距。
总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距
元素的总高度最终计算公式是这样的:
总元素的高度=高度+顶部填充+底部填充+上边框+下边框+上边距+下边距
值 | 说明 |
---|---|
content-box | 默认值。如果你设置一个元素的宽为 100px,那么这个元素的内容区会有 100px 宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。 |
border-box | 告诉浏览器:你想要设置的边框和内边距的值是包含在 width 内的。也就是说,如果你将一个元素的 width 设为 100px,那么这 100px 会包含它的 border 和 padding,内容区的实际宽度是 width 减 去(border + padding) 的值。大多数情况下,这使得我们更容易地设定一个元素的宽高。 **注:**border-box 不包含 margin。 |
inherit | 指定 box-sizing 属性的值,应该从父元素继承 |
任何元素都可以设置border 设置宽高可能无效
行内元素设置padding,margin上下是无效的,左右是有效的
外边距合并:指的是,当两个垂直外边距相遇时,它们将形成一个外边距。
合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
外边距合并(叠加)是一个相当简单的概念。但是,在实践中对网页进行布局时,它会造成许多混淆。
简单地说,外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
当一个元素出现在另一个元素上面时,第一个元素的下外边距与第二个元素的上外边距会发生合并。请看下图:
当一个元素包含在另一个元素中时(假设没有内边距或边框把外边距分隔开),它们的上和/或下外边距也会发生合并。请看下图:
尽管看上去有些奇怪,但是外边距甚至可以与自身发生合并。
假设有一个空元素,它有外边距,但是没有边框或填充。在这种情况下,上外边距与下外边距就碰到了一起,它们会发生合并:
如果这个外边距遇到另一个元素的外边距,它还会发生合并:
子元素宽高设置百分比,是相对于父元素的包含块(一般是content区)来计算,即百分比*父元素包含块宽高
许多开发者认为一个元素的包含块就是他的父元素的内容区,其实这是错误的(至少不完全正确)!
一个元素的尺寸和位置经常受其包含块的影响。大多数情况下,包含块就是这个元素最近的祖先块元素的内容区,但也不是总是这样。
下面我们看看盒模型:
当浏览器展示一个文档的时候,对于每一个元素,它都产生了一个盒子。每一个盒子都被划分为四个区域:
\1. 内容区
\2. 内边距区
\3. 边框区
\4. 外边距区
包含块有分为根元素包含块和其他元素的包含块。
根元素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>
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; }
在这里,这个P标签position为默认的static,所以它的包含块为Section标签,通过我们的判断规则一来确定。
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;
}
在这里,这个P标签position为默认的static且它的父标签Section的display为inline,所以P标签的包含块为body标签,通过我们的判断规则一来确定。
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; }
在这里,这个P标签position为absolute且它的父标签Section的transform不为none,所以P标签的包含块为Section标签,通过我们的判断规则四来确定。
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; }
在这里,这个P标签position为absolute且它的父标签Section的position不为static,所以P标签的包含块为Section标签的padding边缘算起(前提是不能 box-sizing设置为border-box),通过我们的判断规则二来确定。
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; }
在这里,这个P标签position为fixed,所以P标签的包含块为初始包含块(viewport),通过我们的判断规则三来确定。
浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。
**由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样(脱标,不占标准流的空间)。**具有行内块的特性;注意只能压住标准流盒子,不能压住标准流的文字,标准流文字会环绕浮动元素
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79d4Mon8-1646544115489)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220129163512848.png)]
请看下图,当把框 1 向右浮动时,它脱离文档流并且向右移动,直到它的右边缘碰到包含框的右边缘:
再请看下图,当框 1 向左浮动时,它脱离文档流并且向左移动,直到它的左边缘碰到包含框的左边缘。因为它不再处于文档流中,所以它不占据空间,实际上覆盖住了框 2,使框 2 从视图中消失。
如果把所有三个框都向左移动,那么框 1 向左浮动直到碰到包含框,另外两个框向左浮动直到碰到前一个浮动框。
如下图所示,如果包含框太窄,无法容纳水平排列的三个浮动元素,那么其它浮动块向下移动,直到有足够的空间。如果浮动元素的高度不同,那么当它们向下移动时可能被其它浮动元素“卡住”:
浮动不占标准流的空间,但是当要浮动的元素上方有不浮动的元素时,浮动元素不会覆盖上面的元素,即浮动只会影响浮动盒子后面的标准流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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)]
在 CSS 中,我们通过 float 属性实现元素的浮动。
如需更多有关 float 属性的知识,请访问参考手册:CSS float 属性。
浮动框旁边的行框被缩短,从而给浮动框留出空间,行框围绕浮动框。
因此,创建浮动框可以使文本围绕图像:
要想阻止行框围绕浮动框,需要对该框应用 clear 属性。clear 属性的值可以是 left、right、both 或 none,它表示框的哪些边不应该挨着浮动框。
为了实现这种效果,在被清理的元素的上外边距上添加足够的空间,使元素的顶边缘垂直下降到浮动框下面:
这是一个有用的工具,它让周围的元素为浮动元素留出空间。
让我们更详细地看看浮动和清理。假设希望让一个图片浮动到文本块的左边,并且希望这幅图片和文本包含在另一个具有背景颜色和边框的元素中。您可能编写下面的代码:
.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>
这种情况下,出现了一个问题。因为浮动元素脱离了文档流,所以包围图片和文本的 div 不占据空间。
如何让包围元素在视觉上包围浮动元素呢?需要在这个元素中的某个地方应用 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>
这样可以实现我们希望的效果,但是需要添加多余的代码。常常有元素可以应用 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>
这样会得到我们希望的效果。不幸的是,下一个元素会受到这个浮动元素的影响。为了解决这个问题,有些人选择对布局中的所有东西进行浮动,然后使用适当的有意义的元素(常常是站点的页脚)对这些浮动进行清理。这有助于减少或消除不必要的标记。
事实上,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>
优点:简单,代码少,浏览器兼容性好。
缺点:需要添加大量无语义的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>
方法三:给浮动的元素的容器添加浮动
给浮动元素的容器也添加上浮动属性即可清除内部浮动,但是这样会使其整体浮动,影响布局,不推荐使用。
方法四:使用邻接元素处理
什么都不做,给浮动元素后面的元素添加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>
方法五:使用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>
通过CSS伪元素在容器的内部元素最后添加了一个看不见的空格"020"或点".",并且赋予clear属性来清除浮动。需要注意的是为了IE6和IE7浏览器,要给clearfix这个class添加一条zoom:1;触发haslayout。
方法五:使用CSS的:after,:before双伪元素
top、bottom、left、right
HTML 元素的默认值,即没有定位,遵循正常的文档流对象。
静态定位的元素不会受到 top, bottom, left, right影响。
div.static { position: static; border: 3px solid #73AD21; }
元素的位置相对于浏览器可视窗口是固定位置。即使窗口是滚动的它也不会移动:
p.pos_fixed { position:fixed; top:30px; right:5px; }
Fixed定位使元素的位置与文档流无关,因此不占据空间。
Fixed定位的元素和其他元素重叠。
相对定位元素的定位是相对其正常位置。
h2.pos_left { position:relative; left:-20px; } h2.pos_right { position:relative; left:20px; }
移动相对定位元素,但它原本所占的空间不会改变。
h2.pos_top { position:relative; top:-50px; }
相对定位元素经常被用来作为绝对定位元素的容器块。(当绝对定位元素的父元素)
绝对定位的元素的位置相对于最近的已定位的父元素或者祖先元素(static不算定位),如果元素没有已定位的父元素或者祖先元素,那么它的位置相对于:
h2 { position:absolute; left:100px; top:150px; }
absolute 定位使元素的位置与文档流无关,因此不占据空间。
absolute 定位的元素和其他元素重叠。
sticky 英文字面意思是粘,粘贴,所以可以把它称之为粘性定位。
position: sticky; 基于用户的滚动位置来定位。
粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position: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>
值 | 描述 |
---|---|
baseline | 默认。元素放置在父元素的基线上。 |
sub | 垂直对齐文本的下标。 |
super | 垂直对齐文本的上标 |
top | 把元素的顶端与行中最高元素的顶端对齐 |
text-top | 把元素的顶端与父元素字体的顶端对齐 |
middle | 把此元素放置在父元素的中部。 |
bottom | 使元素及其后代元素的底部与整行的底部对齐。 |
text-bottom | 把元素的底端与父元素字体的底端对齐。 |
length | 将元素升高或降低指定的高度,可以是负数。 |
% | 使用 “line-height” 属性的百分比值来排列此元素。允许使用负值。 |
inherit | 规定应该从父元素继承 vertical-align 属性的值。 |
转换后不会影响原有布局,原有位置保留,转换元素,但它原本所占的空间不会改变。(类似于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简写时顺序若有位移先写位移(先旋转会改变坐标轴)
定义动画
//使用%来划分动画间隔
@keyframes myfirst
{
0% {background: red;}
25% {background: yellow;}
50% {background: blue;}
100% {background: green;}
}
//或者使用from to
@keyframes myfirst
{
from {background: red;}
to {background: yellow;}
}
调用动画
div
{
animation:myfirst 5s; //调用动画
-moz-animation:myfirst 5s; /* Firefox */
-webkit-animation:myfirst 5s; /* Safari and Chrome */
-o-animation:myfirst 5s; /* Opera */
}
CSS是一门非程序式语言,没有变量、函数、SCOPE(作用域)等概念
Less(Leaner Style Sheets)的缩写,是一门CSS扩展语言,也称为CSS预处理器
Less在CSS的语法基础上,引入了变量,Mixin(混入),运算以及函数等功能,大大简化了CSS的编写,降低了CSS的维护成本
Less中文网址:http://lesscss.cn/
常见的CSS预处理器:Sass、Less、Stylus
总结:Less是一门CSS预处理语言,它扩展了CSS的动态特性
首先新建一个后缀名为.less的文件,在这个.less文件里面书写Less语句
Less变量、Less编译、Less嵌套、Less运算
语法:@变量名: 值;
变量命名规范:必须有@为前缀、不能包含特殊符号、不能以数字开头、大小写敏感
使用规范:body {color: @color;}
Less包含一套自定义的语法及一个解析器,用户根据这些语法定义自己的样式规则,这些规则最终通过解析器编译成对应的CSS文件
nodejs方法:在当前文件夹,使用cmd命令“lessc style.less > style.css”
vscode插件:Easy LESS插件(只要保存一下Less文件,会自动生成CSS文件)
子元素的样式直接写到父元素里面
.header {
width: 200px;
.logo {
width: 100px;
}
}
如果遇见交集 / 伪类 / 伪元素选择器,内层选择器的前面需要加&符号,被解析为父元素自身或父元素的伪类(若没有&符号,会被解析为父选择器的后代)
a{
&.box {
color: red;
}
&:hover {
color: blue;
}
}
任何数字、颜色或者变量都可以参与运算,Less提供了+ - * / 算术运算
@width: 10px + 5;
div {
width: (@width + 5) * 2;
height: (300px / 50);
border: @width solid red;
background-color: #999 - #333;
}
注意事项:
原因(不准确,仅供参考,记住结果就行):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)
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
<!-- `width=device-width` 会导致 iPhone 5 添加到主屏后以 WebApp 全屏模式打开页面时出现黑边 -->
注意,很多人使用initial-scale=1到非响应式网站上,这会让网站以100%宽度渲染,用户需要手动移动页面或者缩放。如果和initial-scale=1同时使用user-scalable=no或maximum-scale=1,则用户将不能放大/缩小网页来看到全部的内容。
-webkit-tap-highlight-color:transparent //取消点击高亮
通常设置body宽度为100%,其他需要适应屏幕变化的子元素设置为百分比
Flex 布局语法教程 | 菜鸟教程 (runoob.com)
Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。
任何一个容器都可以指定为Flex布局。
.box{
display: flex;
}
行内元素也可以使用Flex布局。
.box{
display: inline-flex;
}
Webkit内核的浏览器,必须加上-webkit前缀。
.box{
display: -webkit-flex; /* Safari */
display: flex;
}
注意,设为Flex布局以后,子元素的float、clear和vertical-align属性将失效。
采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。
容器默认存在两根轴:水平的主轴(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
flex-direction属性决定主轴的方向(即项目的排列方向)。
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
它可能有4个值。
- row(默认值):主轴为水平方向,起点在左端。
- row-reverse:主轴为水平方向,起点在右端。
- column:主轴为垂直方向,起点在上沿。
- column-reverse:主轴为垂直方向,起点在下沿。
默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
它可能取三个值。
(1)nowrap(默认):不换行。
(2)wrap:换行,第一行在上方。
(3)wrap-reverse:换行,第一行在下方。
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
.box {
flex-flow: <flex-direction> <flex-wrap>;
}
justify-content属性定义了项目在主轴上的对齐方式。
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。
- flex-start(默认值):左对齐
- flex-end:右对齐
- center: 居中
- space-between:两端对齐,项目之间的间隔都相等。
- space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
align-items属性定义项目在交叉轴上如何对齐。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
- flex-start:交叉轴的起点对齐。
- flex-end:交叉轴的终点对齐。
- center:交叉轴的中点对齐。
- baseline: 项目的第一行文字的基线对齐。
- stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
该属性可能取6个值。
- flex-start:与交叉轴的起点对齐。
- flex-end:与交叉轴的终点对齐。
- center:与交叉轴的中点对齐。
- space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
- space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
- stretch(默认值):轴线占满整个交叉轴。
https://blog.csdn.net/sinat_27088253/article/details/51532992
以下6个属性设置在项目上。
- order
- flex-grow
- flex-shrink
- flex-basis
- flex
- align-self
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
.item {
order: <integer>;
}
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
.item {
flex-grow: <number>; /* default 0 */
}
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
.item {
flex-shrink: <number>; /* default 1 */
}
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
负值对该属性无效。
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
.item {
flex-basis: <length> | auto; /* default auto */
}
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
该属性可能取6个值,除了auto,其他都与align-items属性完全一致。
rem(root em)是一个相对单位,类似于em,em是相对于父元素字体大小
rem的基准是相对于html元素的字体大小
rem的优势:整个页面只有一个html,可以通过修改html里面的字体大小来改变页面中元素的大小,可以整体控制
CSS3 多媒体查询 | 菜鸟教程 (runoob.com)
媒体查询(Media Query),CSS3的新语法
@media mediatype and|not|only (media feature) { CSS-Code; }
注意:@media开头,media feature媒体特性必须有小括号包含
将不同的终端设备划分成不同的类型,称为媒体类型
值及解释说明
all:用于所有设备
print:用于打印机和打印预览
screen:用于电脑屏幕,平板电脑,智能手机等
关键字将媒体类型或多个媒体特性连接到一起作为媒体查询的条件
and:可以将多个媒体特性连接到一起,相当于“且”的意思
not:排除某个媒体类型,相当于“非”的意思,可以省略
or:可以测试多个媒体查询的条件,只要有一个条件成立,就执行,“或”的意思
only:指定某个特定的媒体类型,可以省略
根据不同媒体类型的媒体特性设置不同的展示风格,先了解三个,注意加小括号包含
width:定义输出设备中页面可见区域的宽度
min-width:定义输出设备中页面最小可见区域的宽度
max-width:定义输出设备中页面最大可见区域的宽度
rem单位是跟着html来走的,有了rem页面元素可以设置不同大小尺寸
媒体查询可以根据不同设备宽度来修改样式
媒体查询+rem就可以实现不同设备宽度,实现页面元素大小的动态变化
让一些不能等比自适应的元素,达到当设备尺寸发生改变时,等比例适配当前设备
使用媒体查询根据不同设备按比例设置html的字体大小,然后页面元素使用rem做尺寸单位,当html字体大小变化元素尺寸也会发生变化,从而达到等比缩放的适配
弱类型语言,即变量的数据类型由=右边的值动态确定,执行过程中可以变化
解释性语言,即解释一行执行一行
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)]
undefined:
在 JavaScript 中, undefined 是一个没有设置值的变量。
typeof 一个没有值的变量会返回 undefined。
null:
在 JavaScript 中 null 表示 “什么都没有”。
null是一个只有一个值的特殊类型。表示一个空对象引用。
undefined和null的区别:
● undefined
表示一个变量没有被声明,或者被声明了但没有被赋值(未初始化),一个没有传入实参的形参变量的值为undefined,如果一个函数什么都不返回,则该函数默认返回undefined。null
则表示“什么都没有”,即“空值”。
● Javascript将未赋值的变量默认值设为undefined
;Javascript从来不会将变量设为null
。它是用来让程序员表明某个用var声明的变量时没有值的;
● undefined
不是一个有效的JSON,而nul
l是;
● null
和 undefined
的值相等,但类型不等:undefined的类型(typeof)是undefined
;null的类型(typeof)是object
。
null == undefined // true
null === undefined // false
typeof undefined // undefined
typeof null // object
● null
和undefined
之间的主要区别在于它们被转换为原始类型的方式。
在’null’上执行算术转换时,则值为0,可以使用以下代码片段验证此转换。
var v1= 5+ null;
console.log(v1)
执行时,此代码的将输出
5
但是,“undefined”不执行任何此类转换。如果您尝试将“undefined”添加到数字中,您将获得NaN或Not-a-Number。以下代码片段说明了“undefine”的这一方面。
var v2= 5+ undefined;
console.log(v2)
执行时,代码将输出:
NaN
null == 0 //false null == "" //false null == false //false undefined == 0 //false undefined == "" //false undefined == false //false undefined == null //注意!注意!注意! //true undefined === null //注意!注意!注意! //false
‘’、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
两等号判等,会在比较时进行类型转换;
三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回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
对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:
arguments[0]
arguments[1]
arguments[2]
复制代码
参数也可以被设置:
arguments[0] = 'value';
复制代码
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]; // 方式二
复制代码
arguments.callee()
)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
复制代码
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
局部变量:在函数中通过var声明的变量。代码块运行结束后就会被销毁
function func(){
var temp=10
}
全局变量:在函数外通过var声明的变量。浏览器关闭时才销毁
var temp=10
没有声明就使用的变量,默认为全局变量,不论这个变量在哪被使用。
//函数外直接使用
temp=10
//函数内直接使用
function func(){
temp=10
}
(es6)块级作用域:const和let;let 的声明方式与 var 相同,用 let 来代替 var 来声明变量,就可以把变量限制在当前代码块中。
{
let temp=10
}
console.log(temp)//报错
{
const temp=10
}
console.log(temp)//报错
作用域链其实是一个很简单的概念,当我们使用一个变量时,先在当前作用域查找,如果没找到就去他外层作用域查找,如果还没有,就再继续往外找,一直找到全局作用域,如果最终都没找到,就报错。比如如下代码:
let x = 1;
function f() {
function f1() {
console.log(x);
}
f1();
}
f();
这段代码在f1
中输出了x
,所以他会在f1
中查找这个变量,当然没找到,然后去f
中找,还是没找到,再往上去全局作用域找,这下找到了。这个查找链条就是作用域链。
原理:只提升声明,不提升赋值
var a=b=c=9;
//等价于
var a=9;
b=9;
c=9;
在ES6之前,我们申明变量都是使用var
,使用var
申明的变量都是函数作用域,即在函数体内可见,这会带来的一个问题就是申明提前。
var x = 1;
function f() {
console.log(x);
var x = 2;
}
f();
上述代码的输出是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();
看下面这个代码:
function f() {
x();
function x() {
console.log(1);
}
}
f();
上述代码x()
调用是可以成功的,因为函数的声明也会提前到当前函数的最前面,也就是说,上面函数x
会提前到f
的最顶部执行,上面代码等价于:
function f() {
function x() {
console.log(1);
}
x();
}
f();
但是有一点需要注意,上面的x
函数如果换成函数表达式就不行了:
function f() {
x();
var x = function() {
console.log(1);
}
}
f();
这样写会报错Uncaught TypeError: x is not a function
。因为这里的x
其实就是一个普通变量,只是它的值是一个函数,它虽然会提前到当前函数的最顶部申明,但是就像前面讲的,这时候他的值是undefined
,将undefined
当成函数调用,肯定就是TypeError
。
既然变量申明和函数申明都会提前,那谁的优先级更高呢?答案是**函数申明的优先级更高!**看如下代码:
var x = 1;
function x() {}
console.log(typeof x); // number
上述代码我们申明了一个变量x
和一个函数x
,他们拥有同样的名字。最终输出来的typeof
是number
,说明函数申明的优先级更高,x
变量先被申明为一个函数,然后当我们再用var
申明x
的时候,这个var
会被忽略,但是x=1
的赋值语句会运行,最后x
就是1,类型是number
。
//创建空对象
var obj={}
//创建空对象
var obj=new Object()
创建一个构造函数,专门用来创建Person对象的,构造函数就是一个普通的函数,创建对象和普通函数没有区别,不同的是构造函数习惯上首字母大写
构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
构造函数执行流程:
1.立刻创建一个新的对象
2.将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回
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);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IH0DgLFz-1646544115500)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220205155614579.png)]
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类,我们将通过一个构造函数创建的对象,称为是该类的实例
this的三种情况:
1.当以函数的形式调用时,this是window
2.当以方法的形式调用时,谁调用方法this就是谁
3.当以构造函数的形式调用时,this就是新创建的那个对象
1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8FEycvL-1646544115500)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220205164301519.png)]
js中谁调用指向谁
如:全局中,func()=window.func()中this指向window
btn.sayHi()中this指向btn
es6箭头函数:箭头函数体内的this
对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
(73条消息) js中的this指向问题_qq_45225833的博客-CSDN博客
对象里的方法可以通过this访问对象属性
var obj={
name:"liu",
say:function(){
console.log(this.name)
}
}
基本包装类型,就是把简单数据类型包装成了复杂数据类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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中的数据类型主要分为两大类:原始类型(值类型)和引用类型。常见的数据类型如下图所示:
原始数据类型存在栈中,引用类型在栈中存的是一个引用地址,这个地址指向的是堆中的一个数据对象。需要注意的是null
在这里我们算在原始类型里面,但是你用typeof
的时候会发现他是object
,原因是就算他是一个对象,那他应该在栈中存一个引用地址,但是他是一个空对象,所以这个地址为空,也就是不对应堆中的任意一个数据,他在堆中没有数据,只存在于栈中,所以这里算为了原始类型。引用类型其实主要就是Object
,Array
和Function
这些其实也都是Object
派生出来的。关于这两种类型在内存中的更详细的知识可以看这篇文章。
下面我们来看看这两种类型的区别:
原始类型的值无法更改,要更改只能重新赋值。像下面这样尝试去修改是不行的,但是整个重新赋值可以。
原始类型的比较就是比较值,值相等,他们就相等
引用类型的值是可以修改的,注意这个时候我们虽然修改了a
里面的属性,但是a
在栈上的引用地址并没有变化,变化的是堆中的数据。
引用类型的比较是比较他们的索引地址,而不是他们的值。比如下面两个对象,看着是一样的,但是他们的引用地址不一样,其实是不等的:
要想让他们相等,得直接将b
赋值为a
,这样他们的引用地址一样,就是相等的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDvNNPjo-1646544115504)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220206011653408.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
在 HTML DOM (Document Object Model) 中 , 每一个元素都是 节点:
通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML。
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() 添加可以添加多个事件
捕获:由外向内
冒泡:由内向外
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LG1jwKiY-1646544115508)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220207162656511.png)]
BOM包含DOM
HTML DOM 事件对象 | 菜鸟教程 (runoob.com)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
{
var foo = 'bar'
}
console.log(foo)
if (true) {
var a = 123
}
console.log(a)
作用域链示例代码:
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:
var arr = [10, 20, 30]
for(var i = 0; i < arr.length; i++) {
arr[i] = function () {
console.log(i)
}
}
示例2:
console.log(111)
for(var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 0)
}
console.log(222)
思考题 1:
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
};
}
};
console.log(object.getNameFunc()())//结果:The Window
思考题 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
js 函数的防抖(debounce)与节流(throttle) - shiweiqianju - 博客园 (cnblogs.com)
js库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEVfznDI-1646544115508)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209131529047.png)]
jQuery对象只能使用jQuery方法,DOM对象只能使用原生的JavaScript属性和方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMCIN7Bz-1646544115509)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209131905694.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IT9NPCm1-1646544115510)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220209134525226.png)]
jQuery 提供多个处理尺寸的重要方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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没变,那就是深拷贝,自食其力。
var a = 1;
b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的
b = 2;
console.log(a); // 1
当然,这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。
image.png
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
image.png
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
image.png
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
image.png
(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
(2)Object.assign方法
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3
(3)直接用=赋值
let a=[0,1,2,3,4],
b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
image.png
(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);
结果:
image.png
(2) 通过JSON对象来实现深拷贝
function deepClone2(obj) {
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
缺点: 无法实现对对象中方法的深拷贝,会显示为undefined
(3)通过jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
(4)lodash函数库实现深拷贝
let result = _.cloneDeep(test)
(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
}
(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
(7)如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign({}, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a);// 1
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 );
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
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;
}
(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米" }
强类型语言
自行复习
https://es6.ruanyifeng.com/
1.1 ES6 教程 | 菜鸟教程 (runoob.com)
let 允许创建块级作用域,ES6 推荐在函数中使用 let 定义变量,而非 var:
var a = 2;
{
let a = 3;
console.log(a); // 3
}
console.log(a); // 2
{
let a = 3;
console.log(a); // 3
}
console.log(a); // 报错a is not defined
同样在块级作用域有效的另一个变量声明方式是 const,它可以声明一个常量。ES6 中,const 声明的常量类似于指针,它指向某个引用,也就是说这个「常量」并非一成不变的,如:
{
const ARR = [5,6];
ARR.push(7);
console.log(ARR); // [5,6,7]
ARR = 10; // TypeError
}
有几个点需要注意:
const array=[1,2,3];
array.push(4); //不会报错
array=4 //报错
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
尚硅谷Web前端ES6教程,涵盖ES6-ES11_哔哩哔哩_bilibili
ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体:
var getPrice = function() {
return 4.55;
};
// Implementation with Arrow Function
var getPrice = () => 4.55;
需要注意的是,上面例子中的 getPrice 箭头函数采用了简洁函数体,它不需要 return 语句,下面这个例子使用的是正常函数体:
let arr = ['apple', 'banana', 'orange'];
let breakfast = arr.map(fruit => {
return fruit + 's';
});
console.log(breakfast); // apples bananas oranges
当然,箭头函数不仅仅是让代码变得简洁,函数中 this 总是绑定总是指向对象自身。具体可以看看下面几个例子:
function Person() {
this.age = 0;
setInterval(function growUp() {
// 在非严格模式下,growUp() 函数的 this 指向 window 对象
this.age++;
}, 1000);
}
var person = new Person();
我们经常需要使用一个变量来保存 this,然后在 growUp 函数中引用:
function Person() {
var self = this;
self.age = 0;
setInterval(function growUp() {
self.age++;
}, 1000);
}
而使用箭头函数可以省却这个麻烦:
function Person(){
this.age = 0;
setInterval(() => {
// |this| 指向 person 对象
this.age++;
}, 1000);
}
var person = new Person();
// 回调函数 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
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TAWhv43R-1646544115516)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210155736517.png)]
function pp(){
console.log('p',this) //this指向window
}
pp();
从左向右依次赋值
ES6 中允许你对函数参数设置默认值:
let getFinalPrice = (price, tax=0.7) => price + price * tax;
getFinalPrice(500); // 850
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
当被用于函数传参时,是一个 Rest 操作符:
function foo(...args) {
console.log(args);
}
foo( 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] // }
ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者0O 即可将其转换为八进制值:
let oValue = 0o10;
console.log(oValue); // 8
let bValue = 0b10; // 二进制使用 `0b` 或者 `0B`
console.log(bValue); // 2
拓展运算符(…)用于取出参数对象(也可用于数组)所有可遍历属性然后拷贝到当前对象。
数组可以直接使用…array;对象只能在对象中使用{…obj}
基本用法
let person = {name: "Amy", age: 15}; let someone = { ...person }; someone; //{name: "Amy", age: 15}
可用于合并两个对象
let age = {age: 15}; let name = {name: "Amy"}; let person = {...age, ...name}; person; //{age: 15, name: "Amy"}
注意点
自定义的属性和拓展运算符对象里面属性的相同的时候:自定义的属性在拓展运算符后面,则拓展运算符对象内部同名的属性将被覆盖掉。
let person = {name: "Amy", age: 15}; let someone = { ...person, name: "Mike", age: 17}; someone; //{name: "Mike", age: 17}
自定义的属性在拓展运算度前面,则变成设置新对象默认属性值。
let person = {name: "Amy", age: 15}; let someone = {name: "Mike", age: 17, ...person}; someone; //{name: "Amy", age: 15}
拓展运算符后面是空对象,没有任何效果也不会报错。
let a = {...{}, a: 1, b: 2}; a; //{a: 1, b: 2}
拓展运算符后面是null或者undefined,没有效果也不会报错。
let b = {...null, ...undefined, a: 1, b: 2}; b; //{a: 1, b: 2}
从左到右解构
基本
let [a, b, c] = [1, 2, 3]; // a = 1 // b = 2 // c = 3
可嵌套
let [a, [[b], c]] = [1, [[2], 3]]; // a = 1 // b = 2 // c = 3
可忽略
let [a, , b] = [1, 2, 3]; // a = 1 // b = 3
不完全解构
let [a = 1, b] = []; // a = 1, b = undefined
剩余运算符
let [a, ...b] = [1, 2, 3]; //a = 1 //b = [2, 3]
字符串等
在数组的解构中,解构的目标若为可遍历对象,皆可进行解构赋值。可遍历对象即实现 Iterator 接口的数据。
let [a, b, c, d, e] = 'hello'; // a = 'h' // b = 'e' // c = 'l' // d = 'l' // e = 'o'
解构默认值
let [a = 2] = [undefined]; // a = 2
当解构模式有匹配结果,且匹配结果是 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
基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb'
let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd'
可嵌套可忽略
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'
不完全解构
let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj; // x = undefined // y = 'world'
剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; // a = 10 // b = 20 // rest = {c: 30, d: 40}
解构默认值
let {a = 10, b = 5} = {a: 3}; // a = 3; b = 5;
let {a: aa = 10, b: bb = 5} = {a: 3}; // aa = 3; bb = 5;
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
ES6 中有一种十分简洁的方法组装一堆字符串和变量。
let user = 'Barret';
console.log(`Hi ${user}!`); // Hi Barret!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J4Dcjr5y-1646544115517)(C:\Users\王畅\AppData\Roaming\Typora\typora-user-images\image-20220210153452156.png)]
for…of 用于遍历一个迭代器,如数组:
let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname of nicknames) {
console.log(nickname);
}
// 结果: di, boo, punkeye
for…in 用来遍历对象中的属性:
let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname in nicknames) {
console.log(nickname);
}
Result: 0, 1, 2, size
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
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'
key 是对象
var myMap = new Map();
var keyObj = {},
myMap.set(keyObj, "和键 keyObj 关联的值");
myMap.get(keyObj); // "和键 keyObj 关联的值"
myMap.get({}); // undefined, 因为 keyObj !== {}
key 是函数
var myMap = new Map();
var keyFunc = function () {}, // 函数
myMap.set(keyFunc, "和键 keyFunc 关联的值");
myMap.get(keyFunc); // "和键 keyFunc 关联的值"
myMap.get(function() {}) // undefined, 因为 keyFunc !== function () {}
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"
虽然 NaN 和任何值甚至和自己都不相等(NaN !== NaN 返回true),NaN作为Map的键来说是没有区别的。
对 Map 进行遍历,以下两个最高级。
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 对象中每个元素的值。 */
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)
Map 与 Array的转换
var kvArray = [["key1", "value1"], ["key2", "value2"]];
// Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象
var myMap = new Map(kvArray);
// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
var outArray = Array.from(myMap);
Map 的克隆
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);
var myMap2 = new Map(myMap1);
console.log(original === clone);
// 打印 false。 Map 对象构造函数生成实例,迭代出新的对象。
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]);
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
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
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 也能存储
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
数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
并集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
交集
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}
差集
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}
类似于 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 对象已经被删除
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.."
类中的继承和超集:
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
extends 允许一个子类继承父类,需要注意的是,子类的constructor 函数中需要执行 super() 函数。
当然,你也可以在子类方法中调用父类的方法,如super.parentMethodName()。
在 这里 阅读更多关于类的介绍。
有几点值得注意的是:
Symbol 是一种新的数据类型,它的值是唯一的,不可变的。ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符:
var sym = Symbol( "some optional description" );
console.log(typeof sym); // symbol
注意,这里 Symbol 前面不能使用 new 操作符。
如果它被用作一个对象的属性,那么这个属性会是不可枚举的:
var o = {
val: 10,
[ Symbol("random") ]: "I'm a symbol",
};
console.log(Object.getOwnPropertyNames(o)); // val
如果要获取对象 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
迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素时,迭代器便会退出。它提供了 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 }
你可以通过 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
}
上面代码表明,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]);
}
另一个方法是使用 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
也可以手动写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)]
Generator 有两个区分于普通函数的部分:
其中 * 用来表示函数为 Generator 函数,yield 用来定义函数内部的状态。
function* func(){
console.log("one");
yield '1';
console.log("two");
yield '2';
console.log("three");
return '3';
}
调用 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}
第一次调用 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));
}
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}
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}
除了使用 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
遍历器对象抛出了两个错误,第一个被 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; } } }
ES6 对 Promise 有了原生的支持,一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者rejected。
var p = new Promise(function(resolve, reject) {
if (/* condition */) {
// fulfilled successfully
resolve(/* value */);
} else {
// error, rejected
reject(/* reason */);
}
});
每一个 Promise 都有一个 .then 方法,这个方法接受两个参数,第一个是处理 resolved 状态的回调,一个是处理 rejected 状态的回调:
p.then((val) => console.log("Promise Resolved", val),
(err) => console.log("Promise Rejected", err));
自己学习
webpack是前端项目工程化的具体解决方案。
主要功能:它提供了友好的前端模块化开发支持,以及代码压缩混淆、处理浏览器端JavaScript的兼容性、性能优化等强大的功能。
1: 就是"基础库"或者"基础组件", 意思就是把重复的代码部分提炼出一个个组件供给功能使用
2: 功能相对单一或者独立, 在整个系统的代码层次上位于最底层,被其他代码所依赖,所以说组件化是纵向分层。
3: 使用场景: 是对一些重复代码进行封装在需要的时候调用即可(例如: 按钮, 输入框, 搜索框)
4: 目得: 复用, 解耦
1: 就是"业务框架"或者"业务模块", 将不同的业务进行划分, 同一类型的整合在一起, 所以功能会相对复杂, 但是都属于同一个业务
2: 按照项目功能需求划分成不同类型的业务框架(例如:注册、登录、外卖、直播.....)
3: 目得: 隔离.分装, 模块之间有依赖的关系, 可以通过路由进行模块直接的耦合问题
组件:就像一个个小的单位,多个组件可以组合成组件库,方便调用和复用,组件间也可以嵌套,小组件组合成大组件。
模块:就像是独立的功能和项目(如淘宝:注册、登录、购物、直播…),可以调用组件来组成模块,多个模块可以组合成业务框架。
使用组件化和模块化的好处 :
开发和调试效率高:随着功能越来越多,代码结构会越发复杂,要修改某一个小功能,可能要重新翻阅整个项目的代码,把所有相同的地方都修改一遍,重复劳动浪费时间和人力,效率低;使用组件化,每个相同的功能结构都调用同一个组件,只需要修改这个组件,即可全局修改。
可维护性强:便于后期代码查找和维护。
避免阻断:模块化是可以独立运行的,如果一个模块产生了bug,不会影响其他模块的调用。
版本管理更容易:如果由多人协作开发,可以避免代码覆盖和冲突。
数据驱动视图:
双向数据绑定:
在网页中,form 表单负责采集数据,Ajax 负责提交数据。
注意:数据驱动视图和双向数据绑定的底层原理是 MVVM(Mode 数据源、View 视图、ViewModel 就是 vue 的实例)
v-text
指令的缺点:会覆盖元素内部原有的内容!{{ }}
插值表达式:在实际开发中用的最多,只是内容的占位符,不会覆盖原有的内容!v-html
指令的作用:可以把带有标签的字符串,渲染成真正的 HTML 内容!注意:插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中!
在 vue 中,可以使用 v-bind:
指令,为元素的属性动态绑定值;
简写是英文的 :
在使用 v-bind 属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,例如:
<div :title="'box' + index">这是一个 div</div>
v-on:
简写是 @
语法格式为:
<button @click="add"></button>
methods: {
add() {
// 如果在方法中要修改 data 中的数据,可以通过 this 访问到
this.count += 1
}
}
$event
的应用场景:如果默认的事件对象 e 被覆盖了,则可以手动传递一个 $event。例如:
<button @click="add(3, $event)"></button>
methods: {
add(n, e) {
// 如果在方法中要修改 data 中的数据,可以通过 this 访问到
this.count += 1
}
}
也可以不传递直接在函数中使用event
事件修饰符:
.prevent
<a @click.prevent="xxx">链接</a>
.stop
<button @click.stop="xxx">按钮</button>
v-show
的原理是:动态为元素添加或移除 display: none
样式,来实现元素的显示和隐藏
v-if
的原理是:每次动态创建或移除元素,实现元素的显示和隐藏
在实际开发中,绝大多数情况,不用考虑性能问题,直接使用 v-if 就好了!!!
v-if 指令在使用的时候,有两种方式:
直接给定一个布尔值 true 或 false
<p v-if="true">被 v-if 控制的元素</p>
给 v-if 提供一个判断条件,根据判断的结果是 true 或 false,来控制元素的显示和隐藏
<p v-if="type === 'A'">良好</p>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KoHTE0H-1646544115520)(E:\BaiduNetdiskDownload\day4\讲义\lifecycle.png)]
在实例化之后,数据的观测和事件的配置之前的时候调用,此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据
在创建之后使用,主要用于数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。 然而,挂在阶段还没有开始.
用于在挂载之前使用,在这个阶段是获取不到dom操作的,把data里面的数据和模板生成html,完成了data等初始化,注意此时还没有挂在html到页面上
用于挂载之后使用,在这个时候可以获取到dom操作,比如可以获取到ref等,操作的dom, 在这个时候只能调用一次ajax,在这个时候el和data都可以获取的到
在数据更新之前被调用,发生在虚拟DOM重新渲染,可以在该钩子中进一步地更改状态,不会触发重复渲染过程
在由于数据更改导致地虚拟DOM重新渲染会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,但是在服务器端渲染期间不被调用,可以用于监听某些数据的时候使用钩子
在这个时候还是可以用this来获取,可以用于销毁计时器时候使用,为了防止跳转到其它页面该事件还在执行,还可以清除dom事件等
在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁.
特点:
好处:
axios 是一个专注于网络请求的库!
发起 GET 请求:
axios({
// 请求方式
method: 'GET',
// 请求的地址
url: 'http://www.liulongbin.top:3006/api/getbooks',
// URL 中的查询参数
params: {
id: 1
}
}).then(function (result) {
console.log(result)
})
发起 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)
})
在终端下运行如下的命令,创建指定名称的项目:
vue cerate 项目的名称
vue 项目中 src 目录的构成:
assets 文件夹:存放项目中用到的静态资源文件,例如:css 样式表、图片资源
components 文件夹:程序员封装的、可复用的组件,都要放到 components 目录下
main.js 是项目的入口文件。整个项目的运行,要先执行 main.js
App.vue 是项目的根组件。
自行学习
自行学习
自行学习
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。