前端技术栈
2022-02-04 15:19:09 3 举报
AI智能生成
前端思维导图 最新es特性 css flexd grid布局 DOM BOM webServer只是图谱
作者其他创作
大纲/内容
编程知识储备
OOP
AOP
原型链/作用域链
闭包
设计模式
前端常用
策略
代理
装饰
观察者
责任链
单例
工厂
其他设计模式
生成器
原型
适配器
桥接
组合
外观
享元
命令
迭代器
中介者
备忘录
状态
模板方法
访问者
常用设计模式网址
安全
XSS
持久性跨站攻击
反射型/非持久性跨站攻击
CSRF
sql注入
点击劫持
DDOS攻击
http请求劫持
代码质量
JSLint/JSHint/jscs
CSSLint
HTML Validators
git
打包工具
webpack
基础配置
entry
人口
string
object
array
output
path:输出位置
filename:生成的文件名词
占位符[],name可以根绝入口文件key生成对应文件
mode
development
production
模块热替换
概念
依赖图谱
Runtime
Manifest
loader
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件
特性
支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行
可以是同步的,也可以是异步的
运行在 Node.js 中,并且能够执行任何可能的操作
接收查询参数。用于对 loader 传递配置
loader 也能够使用 options 对象进行配置
除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段
插件(plugin)可以为 loader 带来更多特性。
loader 能够产生额外的任意文件。
解析loader,loader的实质
多数情况下,loader 将从模块路径(通常将模块路径认为是 npm install, node_modules)解析
loader 模块需要导出为一个函数,按照约定,loader 通常被命名为 xxx-loader
常用loaders
css/less样式
less-loader
less编译成css
css-loader
css序列化
style-loader
css使用style标签加载到html
postcss-loader
配合postcss使用,是css的工具集
autoprefixer给样式添加前缀
browserslist指定目标浏览器
package.json中配置browerslist:[]
.browerslistrc中配置,一行一个query条件
cssnano压缩css代码
自定义loader
loader本质是一个函数,接受一个source参数,返回一个处理完成后的string,作为下一个loader的参数
plugins
html
html-webpack-plugin
加载html模板
clean-webpack-plugin
打包之前自动清理输出目录
mini-css-extract-plugin
css文件打包成独立css文件
自定义plugin
3.x
4.x
0配置
没有配置文件时也可以打包
大部分时候不符合使用要求,不实用
5.x
配置文件改名
默认webpack配置名为weibpack.confign.js
可以在package.json中使用script定义命令:webpack --config xxxx.config.js,自定义配置文件
rollup
与web区别
更加纯粹
体积更小
不如webpack功能全面、强大
vite
特点
冷启动,启动速度极快
即时热更新
按需编译
原理
基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用
HTML/HTML5
语义化
转移字符
<
>
"
®
©
&trade
样式
CSS/CSS3
grid
flex
概念
容器:父元素
项目:多个直接子元素
主轴:子元素排列的方向,默认为row,横向
交叉轴:与主轴垂直的方向,默认column,从上到下
容器属性
display:flex
父元素变成弹性布局渲染区域
flex-direction
制定主轴方向
row
从左到右
row-reverse
从右到左
column
从上到下
column-reversse
从下到上排列
flex-wrap
自动换行
默认nowarap
父元素空间不够不换行,等比例缩小子项目
wrap
内容放不开就换行
flex-flow
flex-direction和flex-wrap的简写形式
flex-flow:flex-direction flex-warp
justify-content
主轴上的对齐方式
flex-start
主轴起点对齐
flex-end
主轴终点对齐
center
主轴上居中对齐
space-between
两端对齐,中间多个元素等间距分布
space-around
所有元素等间距分布
align-items
交叉轴上的对齐方式
flex-start
交叉轴起点对齐
flext-end
交叉轴终点对齐
center
交叉轴中线居中对齐
stretch
如果项目没有设置尺寸,项目在交叉轴上沾满空间,垂直拉伸
baseline
基线对齐
项目属性
order
定义项目在主轴上的排列顺序
值越小越靠近主轴起点
align-self
单个项目在交叉轴上的对齐方式
flex-shrink
项目的缩小比例
本项目的shrink/所有shrink的和就是缩小占比例
flex-grow
项目的放大比例
如果有剩余空间,值越大所占空间越多
所有项目中本项目的grow/所有grow的和就是所占比例
引用方法
行内样式
style标签内
外部样式表
导入样式
优先级
选择器
id
class
标签
子选择器>
后代选择器(空格)
通用选择器*
兄弟选择器~
第一个兄弟+
伪类
:link
注意顺序
:visited
注意顺序
:hover
注意顺序
:active
注意顺序
:after
:before
:focus
:first-child
:nth-child
display
none
block
inline
不可设置宽、高、边距
inline-block
可设置宽、高、边距,
inline-block的默认对齐方式是vertical-align:baseline
盒模型
BFC
定义
BFC block formatting context 即块级格式化上下文,他是一个独立的渲染区域,只有块级元素参与,他规定了内部
的块级元素如何布局,并且与这个区域之外毫不相干。外部元素也不能影响这个渲染区域内的元素
的块级元素如何布局,并且与这个区域之外毫不相干。外部元素也不能影响这个渲染区域内的元素
BFC是页面上的一个隔离的独立渲染区域,
区域内的子元素不会影响外部的元素,外部的元素也不会影响里面的元素
区域内的子元素不会影响外部的元素,外部的元素也不会影响里面的元素
布局规则
默认内部的块级元素会在垂直方向上一次放置,每个元素独占一行
块级元素垂直方向上的总距离由margin决定。
属于同一个BFC的两个相邻元素在垂直方向上的margin会发生重叠/合并
属于同一个BFC的两个相邻元素在垂直方向上的margin会发生重叠/合并
BFC区域不会与float浮动定义的元素区域重叠
BFC就是页面上的一个隔离的独立渲染区域,渲染区域里面的子元素不会影响外面的元素。外面的元素也不能影响到渲染区域里面的子元素
计算父元素BFC的高度时,内部浮动元素的高度都必须计算在内
创建BFC
display的值是inline-block,flex,inline-flex,table-cell,table-caption
overflow的值不是visible
float的值不是none
position的值不是static或者relative
解决的问题
避免垂直方向margin的合并
问题:垂直方向上,两个元素上下margin相遇 ,两个幻速的距离不等于两个margin的和。
而是等于最大的margin,较小的margin会被合并
而是等于最大的margin,较小的margin会被合并
解决方式: 使用一个外围块元素包裹下方元素,新的外层元素设置overflow:hidden
结果:下方元素的margin-top收到外层BFC渲染区域的阻隔不会影响外部上方元素的margin-bottom。
同理,上方元素的margin-bottom也不能跨过BFC来影响BFC内部元素的margin-top
同理,上方元素的margin-bottom也不能跨过BFC来影响BFC内部元素的margin-top
避免垂直方向margin溢出
问题: 子元素设置margin-top,会超出父元素上边的范围,变成父元素的margin-top
实际上,父元素和子元素之间还是没有距离,这不是想要的效果
实际上,父元素和子元素之间还是没有距离,这不是想要的效果
解决:设置新外层元素overflow:hidden,变成一个BFC
其他解决方案
为父元素添加border,如果不需要border,可以设置颜色透明
为父元素设置padding替换子元素的margin
为父元素内的第一个子元素之前添加一个<table></table>,使用平级的BFC阻隔下方元素的margin
父元素添加::before{content:'', display:table,height:0},使用伪元素生成一个平级BFC阻隔元素
结果:子元素的margin-top收到外层父元素BFC渲染区域的阻隔,不会影响父元素以外的区域了
自适应两栏布局
左固定,右自适应
.left{float:right;width:固定值}
.right{overflow:hidden} 变成BFC渲染区域,就不会与float左侧重叠了
父元素坍塌
问题:父元素不写高度时,子元素使用了浮动,导致父元素高度不被撑起,父元素高度下降露出float的子元素,
父元素的同级元素也会被float元素遮挡
父元素的同级元素也会被float元素遮挡
解决
1. 父元素也使用float,生成BFC渲染区域,强制高度包含float元素
造成新的浮动问题
2. 父元素设置overflow,生成BFC渲染区域,强制高度包含float元素
造成子元素不能超过父元素区域
3. 父元素内部最后的位置添加一个空的子元素,设置clear:both;清楚浮动影响
子主题
lef
对齐总结
水平对齐
前提
父元素必须时块级盒子元素
不可自由嵌套的块级元素:h1-6, caption, p, hr, dt他们之中只能放内联元素
父元素宽度必须已经设定
场景1:子元素时块级元素且不固定宽度
不存在水平居中,因为块级元素没有宽度会充满整个父元素
场景2:子元素时行内元素,宽度由内容撑开
给父元素设置text-align:center
场景3: 子元素时块级元素且设置宽度
给子元素设置margin:auto,自动分配剩余空间
通过计算设置父级元素的padding-left或者padding-right
给父元素和子元素都设置box-sizing:border-box
父元素padding 的值为(父宽-子宽)/2
通过相对于父元素绝度定位
父元素相对定位
子元素left:50%;margin-left:子元素宽的一半
子元素left:50%;transform:translateX(-50%)
垂直居中
前提:父元素时盒子容器
场景1:子元素时行内元素,高度由内容撑开
单行:设置父元素的line-height为其高度来使子元素垂直居中
多行:给子元素设置diaplay:inline-block/inline/table-cell; vertical-align:middle;
同时利用after为元素添加一个height:100%;vertical-align:middle的元素
同时利用after为元素添加一个height:100%;vertical-align:middle的元素
场景2: 子元素使块级元素,但是高度没有设置
方法1:给父元素这是display:inline/inline-block/table-cell;vertical-align:middle来解决
方法2: flexbox;父元素:display:flex;flex-direction:column;justfiy-content:center
场景3: 子元素是块级元素,高度已经设定
方法1计算子元素的margintop或者marginbottom
给父子元素设置box-sizing:border-box
设置子元素margin为(父高-子高)/2
方法2 计算父元素的padding-top或padding-bottom
给父子元素设置box-sizing:border-box
设置父元素padding(父高-子高)/2
方法3 子元素相对于父元素绝对定位
父元素相对定位
子元素高已知:top:50%;margin-top:-子高的一半
子元素高度未知:top:50%;transform:translateY(-50%)
方法4: flex布局
父元素display:flex;flex-direction:column;justify-content:center
垂直和水平都居中
弹性布局
父元素:display:flex;flex-direction:column;justify-content:center;align-items:center
父相子绝
子元素宽高已知
top:50%;left:50%;margin-top:-子高的一半;margin-left:-子宽的一半
子元素宽高未知
top:50%;left:50%;transform:translate(-50%,-50%);
构建三角形
上三角形
{
width:0;
height:0;
border-lef:50px solid transparent;
border-right:50px solid transparent;
border-bottom: 100px solid black;
}
width:0;
height:0;
border-lef:50px solid transparent;
border-right:50px solid transparent;
border-bottom: 100px solid black;
}
下三角形
{
width:0;
height:0;
border-lef:50px solid transparent;
border-right:50px solid transparent;
border-top: 100px solid black;
}
width:0;
height:0;
border-lef:50px solid transparent;
border-right:50px solid transparent;
border-top: 100px solid black;
}
左三角形
{
width:0;
height:0;
border-top:50px solid transparent;
border-bottom:50px solid transparent;
border-right: 100px solid black;
}
width:0;
height:0;
border-top:50px solid transparent;
border-bottom:50px solid transparent;
border-right: 100px solid black;
}
右三角形
{
width:0;
height:0;
border-top:50px solid transparent;
border-bottom:50px solid transparent;
border-left: 100px solid black;
}
width:0;
height:0;
border-top:50px solid transparent;
border-bottom:50px solid transparent;
border-left: 100px solid black;
}
左上三角形
{
width:0;
height:0;
border-top:100px solid black;
border-right: 100px solid transparent;
}
width:0;
height:0;
border-top:100px solid black;
border-right: 100px solid transparent;
}
左下三角形
{
width:0;
height:0;
border-bottom:100px solid black;
border-right: 100px solid transparent;
}
width:0;
height:0;
border-bottom:100px solid black;
border-right: 100px solid transparent;
}
右上三角形
{
width:0;
height:0;
border-top:100px solid black;
border-left: 100px solid transparent;
}
width:0;
height:0;
border-top:100px solid black;
border-left: 100px solid transparent;
}
右下三角形
{
width:0;
height:0;
border-tottom:100px solid black;
border-left: 100px solid transparent;
}
width:0;
height:0;
border-tottom:100px solid black;
border-left: 100px solid transparent;
}
rem/em/px/pt/%/vw/wh/rpx的区别
设备物理像素
pt 屏幕宽/设备分辨率,其中的一份就是1pt
css像素
px
pc机显示器,1px等于0.76个物理像素
手机屏幕,1px = 2pt
以iphone6为标准,物理像素750,分辨率375
px也是一个相对单位
但是手机屏幕大小不一,差异较大,所以不希望所有手机上显示一样大,而是希望能够等比例缩放,所以移动端不用px
rem
以网页根元素html上设置的字体大小为1rem,默认1rem==16px
可以实现响应式布局,通过监听屏幕大小,改变html的字体大小,就可以改变所有元素的大小,以实现响应式布局
em
父元素字体大小为1em
rpx
小程序专用的单位
以iphone6为标准,物理像素750,分辨率375
无论屏幕大小都分成750份,每份就是1rpx
1px = 2pt = 2rpx
可以不同尺寸屏幕下自动适配
vm/vh
vh:不管视口高度多少,都将视口高均分100份,每1份时1vh
vh:不管视口宽度多少,都将视口宽均分100份,每1份时1vw
本质上是百分比,但是有一个固定的参照
%
通常任务子元素的%完全相对于父元素,但并不绝对
子元素的top、bottom设置百分比,是相对于直接非static定位的父元素的高度
子元素的left、right设置百分比,是相对于直接非static定位的父元素的宽度
子元素的padding、margin设置百分比,不论是垂直还是水平方向,都是相对于直接父元素的padding和margin而非width或height
响应式布局
flex
代码简单,布局方便
缺点:如果中间由内容,缩小到最小就不会再小了
grid
兼容性有问题
容器
grid-template-columns、grid-template-rows
设置容器的行、列数
grid-template-colums:100px 100px 100px 三列100px
grid-template-colums:repeate(3, 100px) 同上
固定各自大小,使用多个沾满宽度
grid-template-colums:repeate(auto-fill, 100px)
按份数分配列宽
gird-template-colums:repeat(4, 1fr) 宽度平分4份
gird-template-columbns: 1fr 2fr 3fr 分成3列分别占1/6, 2/6, 3/6
设置最大最小范围
grid-template-colums:1fr minmax(150px, 1fr)表示第二列最小150px,最大1fr
浏览器自己决定长度
grid-template-colums: 100px auto 100px
定义网格线
grid-template-colums:[c1] 100px [c2] 100px [c3]100px[c4]
column-gap, row-gap
各自之间的间距
grid-auto-flow
grid-auto-flow:row;先填满第一行再放入第二行
grid-autp-flow:colum 先填满第一列再放入第二列
justify-content
整个区域,所有项目的水平对齐方式
start, end, center, stretch, space-between, around-between, apace-evenly
align-content
整个区域,所有项目的垂直对齐方式
取值同上
justify-items
单元格内容的水平对齐方式
值:start end center stretch
align-items
单元格内容的垂直对齐方式
值:start end center stretch
项目
grid-column-start、grid-column-end、 grid-row-start、grid-row-end
制定item的具体位置在哪根网格线
grid-column-start:1;grid-column-end:3
表示从第一条网格线到第三个网格线
简写grid-column:1/3
grid-column-start:1;grid-column-end:3;
grid-row-start;1;grid-row-end:3;
grid-row-start;1;grid-row-end:3;
表示跨两行两列的方形区域
简写grid-area:1/1/3/3
justify-self/align-self
当前单元格内容的水平和垂直方向
place-self同时设置水平和垂直方向
父相子绝
结合media查询可以实现响应式布局
缺点:代码写法复杂,布局繁琐
单位rem
首先给根元素设置一个字体大小,
其他尺寸单位都用rem,
监听屏幕大小按比例改变根元素字体大小
其他尺寸单位都用rem,
监听屏幕大小按比例改变根元素字体大小
缺点:大部分浏览器都有一个字体最小值:12px,字体不会再小了
float
容易被挤压换行
媒体查询
通过媒体查询来设置样式是响应式设计的核心
媒体类型
print
打印机
speech
屏幕阅读器等发声设备
screen
屏幕设备总称,包括电脑屏幕、手机屏幕、平板
style
在style标签中通过设置media来设置使用样式的媒体设备
<style media='screen, print'>
link
在link标签上通过media设置使用样式的媒体设备
<link rel='stylesheet' href='xxx.css' media='print'/>
一个css可能同事被多个页面引用,只要用link就要加media有点繁琐
@import
@impart url(xxx.css) screen,print
@media
可以使用@media做到更细的控制,一个样式可以为多个媒体设备定义样式
<style>
@media screen{
h1{
font-size:13px
}
}
@media print{
h1{
font-size:8em;
}
}
</style>
@media screen{
h1{
font-size:13px
}
}
@media print{
h1{
font-size:8em;
}
}
</style>
设备方向orientation
orientation:landscape 横屏
orientation: portrait;竖屏
查询条件
可以使用不同条件限制使用的样式
横屏显示宽度不能超过600px
@media screen and (orientation:landscape) and (max-width:600px){
h1{
font-size:12px
}
}
h1{
font-size:12px
}
}
横屏显示或宽度不能超过600px
@media screen and (orientation: landscape),
screen and (max-width:600px){
h1{
font-size:12px
}
}
screen and (max-width:600px){
h1{
font-size:12px
}
}
既不是横屏,宽度又不小于600px
@media not screen and (orientation:landscape) and (max-width:600px){
h1{
font-size:12px
}
}
h1{
font-size:12px
}
}
not必须写在开头表示后边的条件都不满足才能使用
引入顺序
@import url(xxx.css) screen and (min-width:1200px)
@import url(xxx.css) screen and (min-width:900px)
@import url(xxx.css) screen and (min-width:900px)
永远使用最后一个
因为最小900px包含了最小1200的情况
设备划分
小于768位嘲超小屏幕(手机)
768-992 小屏幕设备(平板)
992-1200 中等屏幕(桌面显示器)
1200以上宽屏设备 (大桌面显示器)
父容器尺寸划分
超小屏幕,设置宽度位100%
小屏幕宽度设置位750
中等屏幕宽度设置为 970
大屏幕宽度设置为1170
响应式字号
rem相对于根元素字体
html{ font-size:100%; }
@media(min-width:640px){body{font-size:1rem;}}
@media(min-width:960px){body{font-size:1.2rem;}}
@media(min-width:1200px){body{font-size:1.5rem;}}
缩放
实现小于12px的字
display:inline-bliock;scale只能缩放行内块或块元素
-webkit-tranform:scal(0.5);定义缩放
-webkit-transform-origin:left top;定义缩放原点为左上角,非左上角会导致padding、margin比例不对
0.5px的线
问题
.half-px{ height:0.5px; } 不同设备,不同浏览器差异较大
解决
.half-px{
height:1px;
transform:scaleY(0.5);
transform-origin:50% 100%;// 防止线模糊
}
height:1px;
transform:scaleY(0.5);
transform-origin:50% 100%;// 防止线模糊
}
更好的解决:svg
.half-svg{
background:none;
height:1px;
background:url("
data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width=’100‘ height='1px'>
<line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line>
</svg>
")
}
background:none;
height:1px;
background:url("
data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width=’100‘ height='1px'>
<line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line>
</svg>
")
}
使用svg中的line元素划线,默认描边宽度stroke-width=1 由于svg的描边属性的1px是物理像素的1px,相等于高清屏的0,5px
也可以使用svg的ret等元素绘制
也可以使用svg的ret等元素绘制
firefox不可使用?把svg转成base64
.half-svg{
background:none;
height:1px;
background:url("
data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width=’100‘ height='1px'>
<line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line>
</svg>
");
background:url("
data:image/svg+xml;base64, xxxxxxxxxxxxxxxxxxxxxxxx
");
}
background:none;
height:1px;
background:url("
data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width=’100‘ height='1px'>
<line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line>
</svg>
");
background:url("
data:image/svg+xml;base64, xxxxxxxxxxxxxxxxxxxxxxxx
");
}
background:url
Sass/LESS/Stylus
sass
变量
$font-stack:Helvetica,sans-serif;
$primary-color:#333;
$primary-color:#333;
嵌套
nav{
url{ margin:0}
li{ display:inline-blockl}
a{ padding: 12px; }
}
url{ margin:0}
li{ display:inline-blockl}
a{ padding: 12px; }
}
属性也可以嵌套
.demo{
font:{
size:30px;
color:red;
}
}
font:{
size:30px;
color:red;
}
}
父级选择器 &
a{
font-weight:bolder;
&:hover{// 设置父元素a的hover属性
text-decoration:underline;
}
}
font-weight:bolder;
&:hover{// 设置父元素a的hover属性
text-decoration:underline;
}
}
父选择器可以连接自定义后缀,&必须放在开头
#main{
color:black;
&-sidebar{
border:1px solid;
}
}
color:black;
&-sidebar{
border:1px solid;
}
}
混合
混合mixin,用来分组那些需要在页面中服用的css生命,可以给mixin传递参数来使mixin更加灵活
@mixin border-radius($radius){
border-radius:$radius;
-ms-border-radius:$radius;
-moz-border-radius:$radius;
-webkit-border-radius:$radius;
}
.box{
@include border-radius(10px)
}
border-radius:$radius;
-ms-border-radius:$radius;
-moz-border-radius:$radius;
-webkit-border-radius:$radius;
}
.box{
@include border-radius(10px)
}
用来解决浏览器前缀非常有用
继承
%message-common{ border:1px solid #ccc; padding:10px; color:#333; }
.message{
@extend %message-common;
}
.success{
@extend %message-common;
border-color:green;
}
.message{
@extend %message-common;
}
.success{
@extend %message-common;
border-color:green;
}
算术运算符
.container{ width:100; }
article[role='main']{
float:left;
width:600px/960px*100%
}
aside[role='complementary']{
float: right;
width: 300px/960px*100%;
}
article[role='main']{
float:left;
width:600px/960px*100%
}
aside[role='complementary']{
float: right;
width: 300px/960px*100%;
}
less和sass的不同
less是基于js的在客户端处理,sass是基于ruby,所以在服务器处理
变量less用@ sass使用$
sass没有全局变量,但在实际中可以把全局变量放在一个文件中,需要时引入,可以添加 !default表示默认
less的作用域会先查找局部定义的变量,没有找到就想上查找
less中的混合(mixin)直接使用class命名,使用时直接使用,sass中的混合需要@mixin name命令,使用时需要@include mixinA()
sass中增加了条件语句和循环语句 @if @else @while @each @for自定义函数@function @return
p{
@if 1+1==2{border:1px solid;}
@5<3{ border:2px dotted;}
}
@if 1+1==2{border:1px solid;}
@5<3{ border:2px dotted;}
}
@if lightness(@color) >30%{
background:#000
}@else{
background:#fff
}
background:#000
}@else{
background:#fff
}
@for $i from 1 to 10{
.border-#{$i}{
border #{$i}px solid blue;
}
}
.border-#{$i}{
border #{$i}px solid blue;
}
}
$i : 6
@while $i>0{
item-#{$i}{ widht:2em*$i; }
$i:$i-2;
}
@while $i>0{
item-#{$i}{ widht:2em*$i; }
$i:$i-2;
}
@each $member in a,b,c,d{
.#{$member}{
background-image:url('/image/#{$member}.jpg')
}
}
.#{$member}{
background-image:url('/image/#{$member}.jpg')
}
}
@function double($n){
@return $n*2
}
#sidbar{
width: double(5px);
}
@return $n*2
}
#sidbar{
width: double(5px);
}
TypeScript
简单数据类型
泛型
内置类型
Partial
类型全部可选
required
属性必选
readonly
属性只读
pick
选取某些属性
keyof
属性的key
Extract
Extract<T, U>T和U取交集
exclude
Exclude<T, U>T中移除U属性
record
Record<K, T>K中的属性标记为T
omit
Omit<K,T>对象类型k中踢除T,生成新对象类型
mutable
与readonly相反,改为可修改
ReturnType<T>
获取函数返回值类型
关键字
interface
type
in
infer
js基础/es6
HTML引入js
HTML使用<script>标签引入javascript
js严格按照<javascriopt>标签顺序被解释,async、defer除外
async属性,标识js脚本异步加载,不会阻塞页面渲染,异步加载不能保证他们的执行顺序
defer立即加载但在页面渲染完成后再执行,推迟原则上按照它们被列出的顺序执行
对于不推迟的脚本,浏览器必须解释完script中的代码,再渲染剩余页面,标签应当放在页面最后</body>之前,可以在页面加载完成再加载js,防止页面出现白屏
内联js,放在标签内部
内部不能出现</script>字符串,在出现时可以使用\转义<\/script>,防止浏览器以为脚本已经结束
外部js使用src属性填写url引入,可以同域或不同域
外部引入js会忽略标签内部代码
推荐使用外部js
1. 可维护性,js代码在另一个目录中有利于维护
2.缓存,浏览器加载过的文件会被缓存,同一个文件只会下载一次,再次使用该文件更快
3. 适应未来.放在外部不用考虑XHTML不兼容的问题、或不支持js脚本浏览器直接显示js代码的问题
XHTML中对<,>会识别成标签
1.需要使用实体形式的<>
使用<![CDATA[xxxxxxxxjs代码xxxxxxx]]块包裹代码,表示文档中可以包含任意文本的区块
noscript
在不支持脚本或关闭脚本支持时宣誓的内容,若浏览器支持并启用脚本,该标签内的元素不会被渲染
语言基础
标识符
标识符区分大小写
以_字母$开头
生下的字符可以是_字母$和数字
不能以保留字和关键字作为标识符
js分号问题
高程中推荐每个语句都写分号
1. 有助于防止省略带来的问题
2. 有助于删除空行压缩代码
3。 解析器会帮助加分号,所以有时能有性能提升
社区有不同建议:认为这是语言风格的不同
1. 现代js很少直接写脚本直接用,而是使用编译器压缩、编译之后使用,浏览器不会花时间在分号上
2. 编译器会帮助我们添加分号和压缩代码
3. 对于可能出问题的代码主要情况是以{ [ ( + -开头的代码会有问题,与其全部都加,不如记住特殊情况
4。 以{[(+-开头的代码分号可以放前面,叫做行首分号
5. 对于有些编译器不能正确添加分号的情况,是编译器的锅。因为ECMA 262 已经规定了ASI(Auto semicolon insertion)规范,即如何自动添加分号
变量
const
声明的同时必须初始化
声明后不可修改
其他与let基本相同
let
作用域
let声明的范围是块作用域,注意和var的区别
同一个作用域中,不能使用let1重复定义同一个变量
使用let声明的全局变量不会称为window的属性,但相应的变量也会在页面的声明周期内续存,要小心重复声明
暂时性死区
因为let作用域为块,所以在let声明之前不能以任何方式来引用未声明的变量,在let声明之前的执行瞬间被称为暂时性死区
for循环定义
var 定义的变量会穿透到for循环块的外部,导致可以读到var内的变量
let在每一次循环时都会声明一个独立变量实例
var
变量提升
使用var定义的变量,声明会自动提升到作用域的顶部,在变量之前取值为undefined,赋值还在原始位置
可以使用var重复定义同一个变量
作用域
var定义的变量会成为包含它的函数的局部变量,注意和let的区别
可以省略var操作符来声明一个全局变量,该全局变量会自动称为window对象的属性
赋值操作:
var a={};
var b=a;
a.x = a = {n:1}
var a={};
var b=a;
a.x = a = {n:1}
注意js引擎会从左到右解析,从右向左执行
解析:a.x解析为a的地址上的x属性(假设地址为0x1234.x),因为x实在a对象内部;a解析为形参a
所以执行就是把{n:1}赋值给a,
a={n:1} 的返回值是{n:1}的地址,然后把这个地址赋值给原来0x1234.x,
也就是0x1234.x={n;1}
a={n:1} 的返回值是{n:1}的地址,然后把这个地址赋值给原来0x1234.x,
也就是0x1234.x={n;1}
数据类型
number
八进制数
以0开头,如果数值超过7按照十进制处理 严格模式下报错
严格模式下使用0o开头,超过7报错
十六进制
0x开头,超过f报错
数值在所有数学操作中都视为十进制数,结果自动转成十进制数
浮点数
浮点数的内存空间是整数的两倍
所以js想方设法的把浮点数转成整数
1.0会转成整数1
1. 转成整数1
大数使用科学计数法表示3.14e7 ==== 31400000
js自动把六位小数的浮点数转换为科学计数法
注意0.1+0.2 =》0.300 000 000 000 000 04
永远不要比较浮点数的相等
理论依据查看范围章节
处理办法
1. 把浮点数转整数,再转回浮点数;例如:(0.1*10+0.2*10)/10
2. 计算结果的插值与Number.EPSILON比较,小于这个数表示差值没有意义,可以理解为相等,例如Math.abs(n1-n2)<Number.EPSILON 就可以理解为相等
十进制转二进制
对十进制/2取余,一直取到0,倒着看余数就是二进制
十进制小数转二进制,乘以2取整,顺序排列。直到小数位为0
计算一下0.1的二进制形式会发现为无线循环小数0.0001100110011001100110011001100110011001100110011001101...
这个无限小数就是浮点数计算不准确的原因
范围
Number.MIN_VALUE
js中能表示的最小值,最接近0的数
Number.MAX_VALUE
理论上能表示的最大值
超过它就会是Infinity
这种说法有问题
Number.MAX_VALUE+1 != Infinity
+10000000也不是
因为按照IEEE754存储标准,大于1.7976931348623158*10**308才会被定义为Infinity
Number.MAX_VALUE只有1.7976931348623157*10**308,还差1*10**292才会超大小
Number.MAX_SAFE_INTEGER
2**53-1
由于数字存储会先把十进制转二进制,再转科学计数法,之后尾数只能存储53位(存储52位,首位1省略不存,所以是53位),再多位数53位之后的会被省略,也就是不安全,最大安全数字为2**53-1 为什么-1,想想3位数最大值是10*2-1就明白了
Number.MIN_SAFE_INTEGER
0-2**53+1
Number.EPSILON
表示1与大于1的最小浮点数之间的差值
2**-52
ϵ或ε 读作:厄普西隆
数字存储理论
分别是1个符号位+11个指数位+52个尾数位
举个例子,如果是5.5这个数字的话,则计算过程是这样的:
5.5 转二进制 =====> 101.1 科学计数法 =====> 1.011*2^2
存入计算机:
符号位:0
指数位:2 加1023 =====> 1025 转二进制 =====> 10000000001
尾数位:1.011 隐去小数点左边的1 =====> 011
举个例子,如果是5.5这个数字的话,则计算过程是这样的:
5.5 转二进制 =====> 101.1 科学计数法 =====> 1.011*2^2
存入计算机:
符号位:0
指数位:2 加1023 =====> 1025 转二进制 =====> 10000000001
尾数位:1.011 隐去小数点左边的1 =====> 011
NaN
Not a Number
表示本来应该返回数值的操作失败了
NaN == NaN false
使用 isNaN来判断
数值转换
Number()
布尔值
true=>1
false=>0
string
含有非数值字符(不是进制标记,开头不是+-)返回NaN
空字符串返回0
开头是0、+、-会忽略0+,-作为负号
number
直接返回
null
0
undefined
NaN
不传参数
0
object
先调用valueOf()方法,转换其返回值
如果是不是原始值,再调用toString()方法,转换返回值
如果是原始值,转换原始值,否则报错
是原始值,直接转原始值,不再调用toString(),
parseInt
第一个字符不是数字、+、-返回NaN
空字符串返回NaN
Number('') === 0
遇到第一个非数字字符截断,后面的被忽略
可以根据第二个参数,指定要解析的是什么进制数,不符合进制数规则返回NaN
parseFloat()
不能指定进制,只能解析十进制
八进制、十六进制等会返回0
string
转义字符
\n
\t
\r
\f
换页
\\
\'
\"
\`
\xnn
十六进制编码nn表示的字符,nn是十六进制0~F例如\x41等于‘A’
\unnn
十六进制编码nnn表示的Unicode字符,其中nnn是十六进制0~F
字符串一旦定义就是不可变的(immutable)
模板字符串
`` 反引号定义
注意字符串模板内的换行和空格都会被保存在字符串内
插值${},调用的是表达式的toString()方法
标签函数
可以自定义插值的行为
定义一个普通函数作为标签函数
参数是一个数组,第一个参数是插值表达式两边和间隔的字符串
剩余参数是各个插值表达式的值
使用
tagfn `xx${1}bb`
原始字符串
获取原始的木模板字面量内容,而不是转义后的字符
String.raw
注意只对模板字符串有效,其他字符串报错
标签函数第一个参数,默认含有原始字符串的数组
object
constructor
用于创建当前对象的函数
hasOwnProperty(name)
判断当前对象实例是否存在给定的属性(不是原型上),参数是字符串或符号
isPropertyof(object)
判断当前对象是否为另一个对象的原型
propertyIsEnumerable
属性是否可以使用
toLocalString
本地化的对象字符串表示
toString
对象的字符串表示
valueOf
返回对象对应的字符串、数值或布尔类型
boolean
使用==会有自动类型转换
false == 0 true
false == '0' true
false == NaN false
true == NaN false
false == undefined false
true == undefined false
false == null false
ftrue == null false
参考数据类型转换
if自动转换和Boolean()相同和==完全不同
Boolean('0') true
Boolean('') false
Boolean(NaN) false
Boolean(null) false
Boolean(undefined) false
undefined
未定义
除了typeof操作符。其他任何情况下使用未声明的变量都会报错
声明之后未初始化
未定义和未初始化是完全不同的两个概念,但他们的typeof都是undefined
和null区别
null是指一个空对象指针,typeof null === ‘object’
undefine是未初始化的变量 typeof undefined === ‘undefined’
undefined == null true
undefined === null false
null
空对象指针
定义将来要存储对象的变量时,建议使用null来初始化
和undefined表面相等,全等为false
symbol
符号实例是唯一、不可变的
用来保存对象属性使用唯一标识符,不会发生属性冲突的危险
创建
let sym = Symbol('xxx')
不能使用new 操作符
全局注册表
Symbol.for()
使用一个z字符串类型的key在全局符号注册表中创建并重用符号
传入的不是字符串会转成字符串
对每个字符串进行幂等操作,第一次使用某个字符串会在全局注册表中查询对应符号,发现没有就是用这个字符串创建一个,下一次使用同样的字符串,就返回这个符号
即使使用同样的符号描述,在全局注册表中注册的符号和Symbal()注册的符号也不等同
Symbol.keyFor()
传入Symbol查询key
符号作为属性
对象字面量
Object.defineProperty
查询对象属性
Object.getOwnPropertyNames()
返回常规属性数组
Object.getOwnPropertySymbols()
返回符号属性数组
Object.getOwnPropertyDescriptors()
返回同时包含常规属性和符号属性描述的对象
reflect.ownKeys()
返回常规属性和符号属性的key
内置符号12
Symbol.asyncIterator
由for-await-of使用的遍历方法
使用for-await-of时,会调用key为Symbol.asyncIterator的函数,这个函数会返回一个实现迭代器API的对象
很多时候这个对象是一个Generator
Symbol.iterator
默认迭代器,由for-of语句调用
Symbol.match
由String.prototype.match方法使用
正则表达式原型上有这个函数的定义
表示用该方法匹配字符串
该方法接受一个参数,就是调用match方法的字符串实例
Symbol.replace
由String.prototype.replace方法使用
正则表达式原型上有这个函数的定义
表示如何替换一个字符串中匹配的字串
接受两个参数,即调用replace方法的字符串实例和替换字符串
Symbol.search
由String.prototype.search调用
正则表达式原型上有这个函数的定义
表示字符串中匹配正则表达式的索引
接受一个参数,就是调用search方法的字符串实例
Symbol.split
一个正则表达式,方法,该方法在匹配正则表达式的索引位置拆分字符串
由String.prototyope.split调用
正则表达式原型上有这个函数的定义
接受一个参数,就是调用split方法的字符串实例
Symbol.hasInstance
由instanceof使用
instanceof操作符会使用Symbol.hasInstance函数来确定关系,这个函数返回一个boolean
Symbol.hasInstance默认在Function的原型上,因此所有函数和类都能调用
可以在继承的类上重写这个方法,自定义instanceof的逻辑
Symbol.isConcatSpreadable
由Array.prototype.concat函数执行时,是否能被它拍平
Symbol.species
一个函数值,该函数作为派生对象的构造函数
用Symbol.species定义静态的获取器(getter),可以覆盖新创建实例的原型定义
Symbol.toPrimitive
由ToPrimative抽象操作使用
定义将对象转换成原始值的方法
Symbol.toStringTag
该属性表示一个字符串,该字符串用于创建对象的默认字符串描述
由Object.prototype.toString()调用
toString()获取对象标识时,会检索Symbol.toStringTag指定的实例标识符,默认为“Object”
就是Object 转string时的[object, object] 中的第二个object
Symbol.unscopables
一个对象,该对象所有的以及继承的属性,都会从关联对象的with环境绑定中排除
with操作符不推荐使用,所以也不推荐使用Symbol.unscopables
bigInt
数据类型转换
隐式转换规则
转原始值(primitive value)即(undefined,null,bool,number,string)
先调用对象的valueOf方法
返回原始值,返回该值
返回不是原始值,调用toString()
返回原始值,返回该值
不是原始值,报错
转字符串String()
Boolean
'true' 'false'
Number
'1234'
object
遵循转原始值
null
'null'
undefined
'undefined'
转数字Number()
Boolean
1 0
string
空返回0
含有非数字字符(不是进制标记、0o、0x,0b,不是+、-)返回NaN
开头是+、-、0会忽略,带有进制标识的会转成对应十进制,有进制标志又不合法对应规则的返回NaN
object
遵循转原始值的流程
null
0
undefined
NaN
转布尔值Boolean()
空字符串‘’,0,false,undefined,null,NaN
false
其他为true
包括object类型,不管valueOf和toString返回什么,都是true
注意'0' 它也是true,这里与==不同。==会先把true=>1,然后'0'=>0,然后1==0返回tfalse
toString()
数组
返回逗号,分隔的字符串
null返回空字符串
undefined返回空字符串
object返回"[object,object]"
函数返回函数的字符串形式
function
函数字符串
object
"[object,object]"
null\undefined
没有toString()方法,会报错
需要转换的操作
===
全等,没有隐式转换,类型和值都要相同
==
string == number
string转成number再比较
boolean == 其他类型
boolean转成number再比较
object 与其他类型比较
其他类型是基本类型
先转原始值,再比较
其他类型是object(包括array、function)
比较地址
null 和 undefined
null == undefined
NaN不和剩余的其他类型相等(==),包括它自身,NaN == NaN false
算数运算符
- * /
类型转成number再计算
+
当有字符串参与时,其他类型转成字符串再参与拼接
比较运算符>,<,>=,<=
类型转number再比较
if判断、while循环
类型转boolean再判断
非!
先转boolean再取反
操作符
一元操作符
++a, --a (前缀++--)
先++--再返回数值
后缀++11
先返回变量,再变量++--
一元+、-
+
相当于转number Number()
-
取负数
位操作符
负数使用二补数(补码存储)
绝对值的二进制先取反码
再+1
~按位取反
即每个数二进制都取反
正数按位取反
10进制转二进制
每位取反,得到一个负数再计算机中表示的补码
补码-1,再取反得到绝对值的二进制表示
再计算十进制计算
负数按位取反
先获取负数的计算机表示形式,即绝对值的补码
在对补码按位取反,获取整数的二进制形式
再计算十进制
计算规则复杂,简单记忆
对十进制取相反数再-1
25按位取反=-26
~-5 == 4
&按位与
二进制对齐按位与
负数还是先取计算机中的表示形式
即绝对值的补码
|按位或
二进制对其或
负数同上
^异或
两位不同返回1
负数同上
<<左移
二进制左移,用0填补右侧空位
其实左移n位,就是扩大了2**n倍,参考十进制左移
>>有符号右移
符号位不跟随移动,其他位移动后左侧补0
>>>无符号右移
正数的无符号右移和有符号右移相同
负数要先找到计算机表示形式,即绝对值的补码,再右移,产生的结果变化非常大
逻辑运算符
!非
操作数转布尔值再取反
!!把数据转布尔值和Boolean()作用一样
&&与
短路操作符
返回不一定是布尔值
第一个操作符是true,返回第二个操作符
||或
短路操作符
返回不一定是布尔值
第一个操作符是false,返回第二个操作符
第一个操作符是true,返回第一个操作符
数学运算
*乘
非数字使用Number()转数字再计算
NaN*任何数==NaN
/除
操作数由NaN返回NaN
%取余
**指数
+
-0加-0==-0
+0加+0 == +0
-0加+0 == +0
操作数有字符串,转字符串拼接
-
+0减+0 == +0
+0 减-0 == -0
-0 减 -0 == +0
有非数字的先转数字
关系运算
>
有操作数是数字,先转数字再比较
都是字符串
比较对应字符编码
注意大写字母都比小写字母小,相同的大小写形式比较,才能符合字母顺序
有object,先转原始值
<
>=
<=
==
!=
===
!==
三元运算符
a>b?a:b
赋值
=
+=
-=
*=
/=
%=
**=
<<=
>>=
>>>=
逗号
let a=1, b=2,c=3
let a = (2,3,1,4) ==>a=4
最后一个值
流程控制
if
while
do-whiel
循环体至少执行一次
switch
每一个条件语句的判断都是===全等
for
for in
枚举对象中的非符号属性
for of
for await of
标签语句
xxx:statement
定义一个xxx标签,和break、contine结合使用返回代码的特定位置
break
结束循环,跳出循环体
break xxx
continue
结束本次循环,进行下一轮循环
continue xxx
with
代码作用域设置为特定对象
块中未定义的变量会搜索with(object)中的object
不推荐使用 ,严格模式报错
变量、作用域、内存
传递参数
函数参数是传值,不是传引用
var变量提升
函数作用域
let、const块级作用域
暂时性死区
垃圾回收机制
js会自动的在变量不会再使用使释放它所占的内存
1. 标记清理
在垃圾回收程序运行时,会标记内存中的所有变量,然后,将在上下文中的变量,以及被变量引用的变量的标记去掉
生下的还有标记的变量就是需要删除的
2. 引用计数
当一块内存A被赋予变量B时,表示这个内存A被引用了1次。当变量B赋予了其他的值,则内存A的引用数减1
垃圾回收运行时,清除被引用数为0的内存
这个算法有问题
循环引用永远不会被清除,如果多次调用相关的代码会导致大量内存不会被释放
性能
由于垃圾回收周期性运行,如果变量又多,会导致性能损失。所以垃圾回收的时间调度很重要
v8在一次完整的垃圾回收之后,会根据活跃对象的数量加上一些余量来确定何时再次垃圾回收
IE7之前的回收机制饱受诟病,因为它定死了一个阈值,比如256个变量、4096个对象/数组字面量和数组槽位或64kb字符串,只要满足其一就运行垃圾回收
问题在于,有时候可能在整个生命周期内都需要这么多的变量,这回导致垃圾回收运行过于频繁
优化:IE7之后,改为动态调优,动态分配阈值,一次垃圾回收运行后,只回收了不到15%的已分配内存,则阈值翻倍,如果回收了超过85%的内存,在阈值重置到默认值
内存管理
为了放置js网页耗尽电脑内存,所以分配给浏览器的内存要比桌面软件少很多,移动浏览器更少
保持内存占用少可以提高性能,也就是在数据不再使用时设置为null,解除引用
const、let提高性能
他们是块级作用域,所以他们可能会更早的被垃圾回收机制回收
内存泄漏
1. 内存保存在全局、一只没有解除引用
2. 定时器引用的变量不会被回收
3.闭包引用的变量不会被回收
use strict 严格模式
严格模式下省略var操作符定义全局变量报错:ReferenceError
不能定义名为eval和arguments的变量
八进制数严格模式下以0o开头,超过7报错,非严格模式0开头,超过7按十进制处理
with语句报错
基本引用类型
对象是某个特定引用类型的实例
Date
Date将日期存储为1970年1月1日零时到现在的毫秒数
Date.parse()
接受"月/日/年" 如"4/9/2021"
接受 "月名 日, 年 "May 5, 2021"
接受ISO扩展格式YYYY-MM-DD __HH:mm:ss
返回该日期表示的毫秒数
Date.UTC
返回毫秒数
接受年、月(0-11)、日(1-31)、时0(0-23)、分、秒、毫秒作为参数
Date.UTC(2000,4,5,17,55,55) 2000年5月5日下午5点55分55秒
new Date()
接受毫秒数作为参数,创建日期对象
当参数不是毫秒数时,根据参数形式先调用Date.parse()或Date.UTC()生成毫秒数,再创建日期
继承的方法
toString()
通常返回带时区的日期和时间,时间24小时制
有浏览器差异,注意输出不同,所以用于显示有问题
toLoclString()
本地日期,返回上午、下午12小时制,不带时区
有浏览器差异,注意输出不同,所以用于显示有问题
valueOf()
返回毫秒数
日期对象比较实际上就是比较valueOf的返回值,因此,比较两个日期对象不用担心比较字符串产生的一些问题
getTime
与valueOf相同返回毫秒数
getFullYear()
返回4位数年
setFullYear()
设置年
getMonth
返回0-11制的月
setMonth
设置月,超过11加年
getDate
返回1-31日
setDate
设置日,超过该月天数加月
getDay
返回星期数,星期日0,星期六6
getHours
返回0-23小数
setHours
设置小时,大于23加日
getMinutes()
获取分钟0-59
setMinutes
设置分钟,超过59加时
getSeconds
获取秒,0-59
setSeconds
设置秒,超过59加分钟
getMilliseconds
获取毫秒数
setMilliseconds
设置毫秒数
getTimezoneOffse
获取分钟制的时区偏移量
RegExp
let expression = /pattern/flags
flags标记用于控制正则表达式的行为
g全局模式,查找字符串的全部内容,遇到匹配内容不结束
i,不区分大小写
m,多行模式,查找到一行文本末尾时会继续查找
y,粘附模式,只查找从lastIndex开始及以后的字符串
u,unicode模式,启用Unicode匹配
s, dotAll模式,表示元字符.匹配任何字符包括\n和\r
字面量表示形式
let expression = /pattern/flags
RegExp构造
new RegExp('xxxx', flag)
参数:正则字符串和模式字符串
注意都是字符串,所以有时候转移需要二次转义
字面量/\w\\hello\\123/ ====>> 传入RegExp的字符串 /\\w\\\\hello\\\\123/
RegExp实例属性
global是否全局匹配
ignoreCase是否忽略大小写
unicode是否开启unicode匹配
sticky是否开启粘滞y标记
mutiline是否设置m标记
dotAll,是否这是s标记
lastIndex
source正则表达式的字面量,注意返回没有前后/
flags返回标记字符串
实例方法
exec
和捕获组配合使用,接受一个字符串参数
没有匹配返回null
有匹配返回一个数组,第一个元素是匹配成功的字符串,之后的是匹配成功的捕获组
index,表示字符串中成功匹配的起始位置
input表示输入的字符串
注意有没有g全局匹配标识,方法的行为不同
有g,每次执行都会在lastIndex基础上向前匹配,直到最后
没有g,lastIndex都是0,每次都返回第一个匹配信息
test
返回是否能够匹配成功,boolean类型
toString
返回正则的字面量形式
toLocalString
和toString相同,返回字面量形式
构造函数/静态属性
input
$_
最后搜索的字符串
lastMatch
$&
最后匹配的文本
lastParen
$+
最后匹配的捕获组
leftContent
$`
input字符串中出现在lastMarch左侧的文本
rightContent
$'
input字符串中出现在lastMarch右侧的文本
$1~$9
1~9个捕获组
注意:构造函数的所有属性都没有web标准,生产环境中使用有危险
包装值类型
以读模式访问原始值步骤
1. 创建一个对应的包装值类型实例
2.执行相应的类方法
3.销毁包装值类型实例
Boolean
const falseObj= new Boolean(false)
不要使用包装值类型,因为包装值类型typeof 为object,在做判断时有迷惑性
falseObj == true
Number
toFixed()
取x位小数,四舍五入
toExponential()
返回科学计数法,参数是小数位数,四舍五入
toPrecision
根据情况返回最合理的输出结果,可能是固定长度也可能是科学计数法
isInteger
是否是整数
(1.00).isInteger==true
isSafaInteger
整数是否在安全 范围内
String
js字符
js字符串由16位码元组成,对于大多数字符来说,16位码元对应一个字符
length属性就是返回字符串包含多少个16位码元
charAt返回给定索引位置的字符,就是查找制定索引位置的16位码元,并返回该码元对应的字符
charAt
返回对应索引的的字符
charCodeAt
返回对应索引的字符编码
fromCharCode
返回根据字符编码得到的字符拼接起来的字符串
codePointAt
返回索引对应的码点
码点是Unicode中对一个字符的完整标识,他可能是16位也可能是32位
注意如果传入的索引不是代理对的开头,会返回错误的结果,可以使用遍历字符串来解决这个问题
fromCodePoint
使用码点创建字符串
由于每个字符都是16位表示,所以对超过16位编码的字符就会无法表述
解决策略是再使用另一个16位一起表示字符,叫做代理对
这时候字符串的方法就会出问题,比如笑脸字符
"ab😊de".length === 6
String.fromCharCode(97,98,55357,56842,100,101) === "ab😊de"
"ab😊de".charAt(1) === b
"ab😊de".charAt(2) ===><?>
这时候索引2和索引3被看成一个代理对,只对应一个字符
normalize
传入规范化策略,返回规范化的字符串
由于有些字符,既可以使用16位表示也可以使用32位表示,甚至还有其他表示方法,虽然字符样子相同,但编码不同因此不相等
为了解决这个问题有4中规范策略
NFKC
NFC
NFKD
NFD
concat
连接字符串,不改变原字符串
+连接更方便
subString
两个参数,1是起始位置,2是结束位置不改变原字符串
负参数会转换成0,会根据两个参数的大小,从小截取到大
subStr
两个参数,1是起始位置,2是多少个字符,不改变原字符串
负参数,第一个参数+length,第二个参数转换成0,后一个参数比前一个参数小,返回''空字符串
slice
两个参数,1是起始位置,2是结束位置,不改变原字符串
负参数会+字符串length,后一个参数比前一个参数小,返回''空字符串
indexOf(s,index)
搜索字符串s,从index 开始向后搜索返回位置,没有找到返回-1
lastIndexOf(s,index)
从末尾查找字符串s,从index向前搜索返回位置,没有找到返回-1
startsWith(s,index)
是否以s开头,第二个参数吧index作为开头
endsWith(s,index)
是否以s结尾,二个参数以index作为结尾
includes(s,index)
从index开始搜索s,返回boolean
trim
删除前后空格,不影响原数据
repeat(num)
返回复制num次的字符串拼接
padStart(num,s)
复制num位的字符串,不够num位在前面使用s填充
padEnd
复制糯米位的字符串,不够num位的在后面填充
解构
字符串解构为数组
字符串由一个Symbol.iterator方法,因此可以使用for-of遍历
toLowerCase
字符串小写
toLocaleLowerCase
某些地区转大小写需要使用地区特定的方法
toUpperCase
字符串大写
toLocaleUpperCase
match
返回与exec相同
search(RegExp)
匹配符合正则的索引位置,没有返回-1
replace
第一个参数是字符串或正则
第一个参数是字符串,只会替换第一个子字符串,替换所有需要使用正则+g标记
第二个参数可以是字符串或函数
字符串能够使用$n,$nn,$&,$`,$'等字符序列
函数必须返回字符串,函数参数有匹配的字符串、开始位置,原始字符串等
split
使用传入的字符分隔成数组
第二个参数可以限制生成的数组大小
localeCompaare()
比较两个字符串返回-1,0,1
按照字母顺序,字符串应该排在字符串参数前头,返回-1
字符串与参数相等返回0
按照字母顺序,字符创排在字符串后头,返回1
html方法
big
fontSize(size)
fontColor(color)
link(url)
会生成html标签,但是生成的不是语义化的标签因此基本不会再使用了,还有一些其他方法不再列举
单例内置对象
Global
isNan
parseInt
parseFloat
isFinite
encodeURI
有效的URI不能包括某些字符比如空格,因此可以使用一下两个方法进行编码
encodeURI不会编码属于URL的特殊字符比如冒号、斜杠、问号、井号
encodeURIComponent
encodeURIComponent会编码发现的所有非标准字符,就连http:中的冒号也会编码
因此他适用于编码URI中的单独组件、比如?后面的某一段
使用encodeURIComponent比encodeURI更多,因为编码查询字符串比编码基准URI次数更多
decodeURI
decodeURI只能对encodeURI解码
decodeURIComponent
只能对encodeURIComponent解码
eval
这个方法是整个ECMAScript中最强大的方法
他就是一个完整的js解释器
接受一个即将执行的js字符串
通过eval执行的代码,属于该调用所在的上下文,这意味着,定义在包含上下文中的变量可以在eval内部被调用
eval内部声明的变量和方法也可以在外部代码引用
这个方法非常危险,这个方法会对xss利用暴露出很大的攻击面,尤其是解释用户输入的内容时,用户恶意的插入会导致网站崩溃
window对象
浏览器将window对象实现为Global对象的代理
全局作用域中声明的变量和函数都成为了window的属性
获取Global对象
Math
Math中进行的计算比直接在js中实现快得多,因为Math对象计算使用了js引擎更高效的实现和处理指令
Math.E
对数基数e
Math.LN10
以10为底的自然对数
Math.LN2
以2为底的自然对数
Matg.LOG10E
以10为底e的对数
Math.PI
π
Math.SQRT2
2的平方根
Math.SQRT1_2
1/2的平方根
Math.min
一组数中的最小值
Math.max
Math.ceil
向上取整
Math.floor
向下取整
Math.round
四舍五入
Math.fround
返回最接近的单精度浮点数表示
某些精度不高的场合下,可以通过两个浮点数转32位浮点数比较来解决564位浮点数比较不正确的问题
random
0~1范围内的随机数,包含0不包含1
abs
绝对值
pow(x,y)
x的y次方
sqrt
平方根
cbrt
立方根
sign
返回数值的符号1,-1,0,-0
trunc
返回整数部分
三角函数
集合引用类型
Array
创建数组
new Array(param)
param如果是数字,那么会创建一个param长度的空数组
如果param是非数字,会把参数当成元素
数组字面量
Array.from
把类数字转成数组
就是任何可迭代的结构都能转成数组
map
set
带length,使用数字作为key的对象,
实现了Symbol.iterator的对象,Symbol.iterator一般是一个生成器
Array.of
把一组参数转换成数组
数组空位
字面量初始化数组时,使用一串逗号来创建空位
var arr = [1,,,,1]
arr.lengthv===5
for-of、Array.from、解构都能取到空位,且空位值为undefined
map方法取不到空位,空位会被忽略
由于行为不一致,因此避免使用空位,可以使用undefined填充
length属性
length不是只读属性
改变length可以在末尾添加或删除元素
检测是否是数组
Array.isArray
value instanceof Array
注意Array实际上是在global中的一个类型,在有多个global(意思是有多个全局上下文,比如网页中多个iframe中,就有多个全局上下文)的环境中,有多个版本的Array构造函数,如果把数组从一个框架传给另一个,导致这个数组的构造函数在两个框架中不一样
arr.__proto__.constructor == Array
arr.__proto__ == Array.prototype
判断原型,缺点是如果普通对象直接换成数组原型,那么判断会不准确
Object.getProtoTypeOf(arr) == Array.prototype
Array.prototype.isPrototypeOf(arr)
Object.prototype.toString.call(arr) === '[Object Array]'
让arr调用最顶级原型Object原型上的toString
迭代器方法
keys()
返回索引迭代器
values()
返回元素迭代器
entries()
返回索引/值对的迭代器
复制和填充
fill(s,startIndex,endIndex)
把s填充入startIndex到endIndex
startIndex和endIndex可以忽略,都没有时全部元素填充为s
只有一个startIndex时,从startIndex开始填充到末尾
填充不会超过数组大小,忽略索引相反,忽略索引过高或过低
copyWithin(index, startIndex, endIndex)
复制startIndex到endIndex的元素到index的位置,并向后覆盖
没有第2,3个参数时,表示从第0个元素开始复制到index
没有endIndex,表示从startIndex复制到最后
填充不会超过数组大小,忽略索引相反,忽略索引过高或过低
转换
toString
返回每个元素的等效字符串,再使用逗号拼接成字符串
toLocalString
它会调用每个元素的toLocalString方法,使用逗号连接成字符串
valueOf
返回数组本身
join
使用参数连接成字符串
push
接受无限多个参数,添加到数组末尾
返回length
pop
删除最后一个元素
返回删除的元素
shift
删除第一项
返回删除的元素
unshift
开头添加任意多个值
返回length
sort
默认将元素转成字符串再排序
会导致位数不同的数字比较有问题
接受一个比较函数
reverse
反向排列
concat
创建一个副本,并把数组参数每一项添加到副本末尾,把非数组直接添加到末尾
返回这个副本
可以定义参数的Symbol.isConcatspreable来强制打平或直接添加到末尾
slice
数组切片
返回start到end 之间的数组副本
splice(startIndex, length, a,b,c)
数组中间插入元素
从startIndex开始删除length个元素,然后再startIndex开始插入a,b,c...
返回删除的元素
indexOf(s,index)
从index开始向后搜索,执行严格相等
lastIndexOf(s,index)
includes(s,index)
执行严格相等,返回boolean
find(function, this)
注意第二个参数,可以制定断言函数内部this的值
断言函数有3个参数,item,index,数组本身
findIndex(fun,this)
注意第二个参数,可以制定断言函数内部this的值
断言函数有3个参数,item,index,数组本身
forEach
参数同find
map
filter
some
every
reduce(fn,initData)
归并函数接受:上一个归并值,当前项,当前索引,数组本身
第二个参数时初始值,有初始值时,归并函数第一次执行时的第一个参数时initData;没有初始值时,归并函数第一次执行时的第一个参数是数组的第一个元素
reduceRight
typed array定型数组
提升向原生库传输数据的效率
Map
创建
new Map()
初始化
传入一个可迭代的对象
需要包含键值对数组,每个键值对数组都会按照迭代顺序插入到新的映射实例中
set()
添加键值对
返回Map实例,因此可以链式调用
get()
通过键获取值
has()
是否含有某个键
delete()
删除键值
clear()
清空Map
size
键值对个数
map.entries
map可以迭代,因此可以解构成数组
forEach
map.keys()
map.values()
map和object
map可以使用任何数据类型作为键,可以使用任何数据类型作为值,object只能用string或number作为key
map使用严格相等的标准来检查键的匹配
Map会维护键值对插入的顺序,object不保证键值对的顺序
内存占用
固定大小的内存,map大约比object多存储50%的键值对
插入性能
相差无几,map快一点,大量插入键值对还是用map更快
查找速度
object更快,尤其使用连续整数作为key的情况下,object可以当成数组,浏览器可以优化内存布局,查询更快
删除
object删除属性需要delete obj.xxx;这是一种不优雅的方法,性能也差
map的删除比插入和查找更快
WeakMap
弱映射
key不会阻止垃圾回收
但只要key存在,value就不会被垃圾回收
因为key随时会被垃圾回收清理,也因此没有遍历迭代键值对的能力
因为key是弱引用类型,因此不能使用原始值作为key,如果使用原始值,就无法区分初始化时使用的字符串字面量和初始化之后使用的字符串是否是一个相等的字符串
可以只能是object或继承自object的类型,是有非对象作为键或报错,值没有限制
原始值可以使用其包装类型作为key
set()
get()
has()
delete()
WeakMap和Map
Map任何值都可以做key,WeakMap只能用对象做key
map可以遍历,WeakMap不能遍历
Map有clear方法,WeakMap没有
Map有size属性,WeakMap没有size属性
Map有keys,WeakMap没有
Map有values,WeakMap没有
Map有entries,WeakMap没有
Set
new Set()
传入可迭代对象
add()
has()
delete()
clear()
size
set可以使用任何数据类型作为值
set不可重复,验证重复性使用的是严格相等
set会维护插入的顺序
values()
keys()
支持解构成数组
entries
原始值数组的去重
Array.from(new Set(arr))
利用Set不可重复的特性
WeakSet
弱映射
其中的值不是正式引用,不会阻止垃圾回收
原始值可以使用其包装类型作为值
has
add
WeakSet和Set
WeakSet的值只能是对象,Set可以使用任何数据类型作为值
WeakSet不可迭代
WeakSet没有clear
没有size
没有keys
没有values
没有entries
迭代器与生成器
迭代器
迭代器模式
即可以把有些结构称为可迭代对象,因为他们实现了正式Iterable接口,而且可以通过迭代器Iterator消费
需要实现Symbol.iterator迭代器工厂函数
每次返回一个迭代器对象,这个对象有一个next()方法
next()方法的返回是一个对象{done:false, value:1}
false表示没有结束迭代,done:true表示迭代结束,value代表值
迭代器对象可以实现一个return方法
表示迭代的钟乳退出需要执行的方法,返回{done:true}
break、continue、return都可以终止循环,并执行return方法
迭代器维护着一个指向可迭代对象的引用,着可以组织垃圾回收可迭代对象
生成器
生成器能够在一个函数块中暂停和恢复代码,能够实现自定义迭代器和实现协程
函数名前加*表示它是一个生成器
箭头函数不能定义生成器
生成器可以作为默认迭代器
生成器返回一个生成器对象
生成器对象实现了迭代器,具有next()方法,每一次调用next都会返回一个类似于迭代器,{done:false,value:1}
生成器的返回值即生成器对象实现了迭代器,因此可以吧它当成可迭代对象直接for-of使用
生成器一开始处于暂停执行suspended状态,未调用next时,生成器函数不会执行
yield可以中断生成器,
中断时函数作用域的状态被保留
yield 关键字退出的生成器处于done:false状态
return xxx;返回的生成器,done:true
yield必须用在生成器函数中,其他位置报错
yield可以返回值和接受值,next()的参数可以传递给yield,第一次next()中的值不会被使用,它代表生成器函数开始执行
yield*
yield*可以增强yield行为,它可以迭代一个可迭代对象,一次产出一个值,yield*和循环yield一个可迭代对象时等价的
yield*实现递归
生成器对象有一个return方法用来关闭生成器,return的值会作为终止迭代器对象的值
throw,throw作为错误处理也能终止生成器,但如果迭代器中处理了错误(try,catch处理)那么生成器可以继续向下 执行不会关闭
对象、类和面向对象编程
面向对象的3个特点:封装、继承、多态
封装
创建对象,有两种形式
1. 对象字面量{}
2. new 构造函数,可以反复创建多个相同结构的对象
继承
所有子对象公用的属性和方法,都要放在构造函数的原型对象中
多态
只要觉得父对象继承来的成员不好用,都可以在子对象中重写同名成员或者函数重载(即同名函数参数不同)
this的八种情况
1. obj.xxx
xxx函数中的this指代obj
2. 函数直接执行
this指代距离调用时最近的函数作用域或者全局作用域
3. 原型上的方法中的this
哪个子对象调用的方法,this就指代谁
4. 匿名函数、回调函数、自执行函数中的this
默认就是window
(function(){...this...})()
arr.forEach(function(){....this....})
5. DOM元素上事假处理函数上的this
指代这个元素
6. Vue中的this
Vue实例
7. 箭头函数中的this
当前函数之外最近的作用域中的this
箭头函数的底层,相当于普通函数.bind()绑定了最近作用域的this
注意bind绑定之后,再次bind或者call、apply都不能再次更换this
8. bind, call, apply
call,apply可以替换this,并且自动执行这个函数
bind()把函数的this一次性绑定,且不能再次更换
定义形式
new Object
对象字面
每个对象都是 Object的实例,继承其toString、toLocalString、valueOf
数据属性
writable
是否可以修改
configurable
是否可以配置,即能否删除属性
value
属性值
enumerable
可否通过for-in循环返回
get
获取函数
set
设置函数
可以通过defineProperty来定义这三个属性,已经定义configurable为false的,不能通过definProperty更改configurable为true
同时修改多个属性
defineProperties
注意,使用Object.defineProperty和 Object.defineProperties定义的属性,其enumable\writable\configurable属性默认都是false
获取属性特性
Object.getOwnPropertyDescriptor(obj, key)
返回一个对象包含属性的configurable,enumberable,writable,get,set,value
Object.getOwnPropertyDescroptors(obj)
返回对象所有属性的描述
对象合并
Object.assign
不能在两个对象之间转移获取函数和设置函数
这个函数的执行过程是,使用src对象的get函数返回值,传递给target对象的set函数来设置值
这是属性的浅拷贝,对于对象属性就会复制对象的引用
执行过程中抛出错误,可能会完成部分复制
对象比较
Object.is
接受两个参数,比较两个参数是否相等
相当于全等比较,但考虑了更多的边界条件
true===1 false
{}==={} false
0===-0 true
+0 === -0 true
Object.is(0,-0) false
Object.is(true, 1) false
对象解构
解构同时定义默认值
const {name, age, address='xxxx'}={name:'xxx', age:15}
对象解构在内部使用了函数ToObject(),这是一个不能在运行环境中直接访问的函数
因为使用ToObject()所以,原始值会转成对象再解构,因此可以解构出许多包装值类型的属性
null和undefined不能解构
解构执行过程中出错,可能会导致部分解构成功,出错位置之后不成功
创建对象
工厂模式
根据参数创建对象并return出来,可以创建多个类似对象
构造函数
按照惯例构造函数的首字母需要大写
new 的执行顺序如下
1.在内存中创建一个新对象
2.这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性
3.构造函数内部的this被赋值为这个新对象,即this指向这个新对象
执行构造函数内部的代码,给新对象添加属性
4.如果构造函数返回空对象,那么返回这个对象,否则返回本来应该返回的对象
构造函数也是函数,除了调用方式不同
构造函数的问题
构造函数生成的函数属性,都不相等,new出来的对象,同一个函数属性不是同一个Function对象
其实使用一个function对象就够用了
要把一个函数共享给构造函数产生的所有对象需要原型模式
new操作符的规则,遇到小括号就执行第一个小括号左边的new
function Foo(){
getName=function(){console.log(1)}
return this
}
Foo.getName=function(){console.log(2)}
Foo.prototype.getName=function(){console.log(3)}
new Foo.getName() ====> new 执行Foo.getName()的结果 ====》2
new Foo().getName() ===>new 先执行new Foo() 再执行getName() ===》3
getName=function(){console.log(1)}
return this
}
Foo.getName=function(){console.log(2)}
Foo.prototype.getName=function(){console.log(3)}
new Foo.getName() ====> new 执行Foo.getName()的结果 ====》2
new Foo().getName() ===>new 先执行new Foo() 再执行getName() ===》3
原型模式
原型上定义的属性和方法可以被对象继承
每个函数都会创建一个prototype属性,它是通过构造函数创建的对象的原型,它上面的方法和属性都会被生成的对象继承,因此可以直接在原型上定义属性和方法,就能复用属性和方法了
理解原型
1。创建函数就会创建一个prototype属性,即原型对象;原型对象上默认有一个constructor属性,指向函数本身,还会有其他后添加的属性
2.调用构造函数产生的对象上面,有一个[[Protpotype]]指针,指向原型对象;并非所有浏览器都能显示的访问[[prototype]],FireFox\Safari\Chrome实现了__prototype__属性可以访问对象的原型对象
3.构造函数、对象实例、对象原型是3个完全不同的对象
4.实例与构造函数没有直接关系,与原型对象有直接关系
原型方法
isPrototyppeOf()
判断一个对象是否是另一个对象的原型
Object.getPrototypeof()
获取对象的原型
Object.setPrototypeOf(obj, src)
指定obj的对象原型是src
setPrototypeOf会造成性能下降,它会设计所有访问了那些修改过[[prototype]]的对象的代码
Object.create(obj)
使用obj作为原型创建一个新对象
hasOwnProperty(key)
属性是不是实例对象属性,原型链上的属性会返回false
原型层级
搜索过程
首先在兑现本身搜索属性,有就返回,没有就去他的原型上找
再给对象添加一个与原型上同名的属性后,访问该属性就不会去搜索原型链上的属性了,即使给属性赋值null或undef也不行,但delete操作符可以
in操作符
for-in会遍历对象上可枚举的所有属性,无论属性实在对象实例上还是在原型上
单独使用in,判断属性是否在对象实例和原型上;准确说法是判断属性能否被对象访问到
Object.keys()
获取可枚举的实例属性
Object.getOwnPropertyNames
获取所有实例属性,不管是否可枚举,但不能返回Symbol属性
Object.getOwnPropertySymbols(obj)
获取实例上的Symbol属性
迭代
for-in和Object.keys
枚举顺序不确定,取决于环境
Object.getOwnPropertyNames\Object.getOwnPropertySymbols\Object.assign
先以升序枚举数字键,再以插入顺序枚举字符串和符号键
Object.values
Object.entries
其他原型语法
1.以字面量替换原型
如果不定义constructor,会导致原型链上缺失constructor,如果再以构造函数判断类型就不可能了
如果简单定义constructior:Person,会导致constructor称为可枚举属性,那么constructor会出现在for-in等循环迭代中
如果既要定义constructor又要不可枚举,那么需要Object.defineProperty,默认或指定enumerable:false
原型的动态性
原型是以指针的形式存储,
对象产生的时候,实例的[[prototype]]属性会在 调用构造函数时自动赋值
如果使用其他对象直接替换原型,那么替换之前产生的对象其prototype指针还会指向原来的原型对象,之后产生的对象实例就会是新的原型对象
这就导致同一个构造函数产生的对象,会有不同的原型方法
原生的对象原型
原生引用类型也是使用的原型模式,因此也可以修改原生对象的原型达到共享属性的目的
不推荐使用:因为可能引发命名冲突,比如一个名称在不同浏览器中可能存在,也可能不存在,也可能意外重写原生的方法
如果真要修改,那么创建一个自定义的类继承原生类型
原型中的问题
由于原型上存储的都是指针
那么原型属性上的引用属性(即object类型)值的改变会引起所有对象对应属性的改变
继承
接口继承
js中不可能实现,因为函数没有签名
实现继承
原型链继承
原型链基本构想
每个构造函数都有一个原型对象,原型上有一个构造函数属性指回构造函数,实例上有一个内部指针指向原型
如果原型是另一个类型的实例,那么这个原型本身有一个内部指针指向另一个原型,相应的另一个原型也有一个指针指向另一个构造函数
这样就行成了一条链状的原型链
问题
包含引用值时,定义在父类内部的引用属性变成了子类原型上的属性
而引用属性使用的是指针,导致一个实例操作了父类中的内部引用,所有的实例该引用属性都会产生变化
也没有办法在不影响所有对象的情况下,把参数传递给父类的构造函数
盗用构造函数/经典继承
思路
在子类的构造函数中调用父类构造函数,使父类中的属性称为子类的一部分
问题
必须在构造函数中定义方法,导致方法不能重用
继承是通过父类构造函数执行继承的,因此也不能访问父类原型上定义的方法
组合继承
思路
组合使用原型继承和经典继承
既在子类内部调用父类的构造函数,获取父类构造函数上定义的属性
又把子类的原型替换成父类的实例,获取父类原型上定义的方法
问题
复杂的继承机制
效率问题:父类构造函数会被调用两次
原型式继承
以一个对象作为原型创建另一个对象
替代方法:Object.create(obj,{config})
规范化的原型式继承,第一个参数是作为原型的对象。
第二个参数是给新对象定义额外属性的对象
问题
引用值浅拷贝
寄生式继承
思路
以一个对象作为原型返回新对象的基础上,再增强这个对象
问题
新对象增强 的属性属于对象实例,不能重用
寄生式组合继承
思路
由于组合继承需要调用两次父类的构造函数,父类构造函数上的所有属性都会放到子类的原型上,没有必要
所以只要拿到父类的原型,再增强这个原型,赋值给子类的原型就可以了
更高效的组合继承,寄生式组合继承是引用类型继承的最佳模式
同样实现代码复杂
类
定义
类声明class Person{}
类表达式const Person = class{}
class 与Function定义的不同
类声明式定义不能提升
函数是函数作用域,class是块级作用域
类的本质
类本质上是一个特殊的函数,它也有prototype属性,原型上的constructor指向类本身
类中定义的constructor函数不会被定义为构造函数
由类生成的实例,对实例使用instanceof Class.constructor,返回false
obj instanceOf Class 返回true
类是一等公民,可以传递给函数参数
实例化
1.在内存中创建一个新对象
2. 这个新对象的[[prototype]]指针被赋值为构造函数的prototype属性
3. 构造函数内部的this被赋值为这个新对象
4.执行构造函数
5.返回该对象
构造函数
每个类都有一个构造函数
不定义构造函数,相当于定义构造函数为空函数
new 操作符会调用构造方法
构造函数默认返回this对象,如果返回的不是this对象,那么new操作符产生的对象与类没有任何关系
类中的构造函数不能直接调用,必须使用new操作符
实例属性和方法
构造函数内部,为this添加的属性都是实例属性和方法
构造函数之外,key=value定义,也是实例属性
原型属性和方法
在构造方法之外,类块中定义的方法作为原型方法
也可定义访问器,get、set作为原型方法
静态属性和方法
static修饰的方法和属性叫做静态属性/方法
静态方法中的this指向class本身
生成器和迭代器
类也可以实现迭代器,可以把类的实例变成可迭代的对象
类的继承
关键字extends
不仅可以继承类,也可以继承不同构造函数
super
派生类可以使用super来引用他们的原型
只能在派生类中使用,仅限于实例方法、构造函数、静态方法内部
构造函数中能够使用super()调用父类的构造函数
静态方法中能够使用super调用父类的静态方法
super是定义了构造函数和静态方法的对象的原型
没有定义构造函数,派生类会自动调用super()
如果派生类定义了构造函数,就必须调用super()或返回一个对象
注意手动返回一个对象,会使new出来的对象和类没有任何关系
构造函数中,super之前不能使用this
因为super()调用后返回的实例才会赋值给this
抽象基类
js中没有专门的抽象基类
使用new.target可以检测new关键字实例化的是哪一个类,从而阻止对抽象类的实例化
由于实例化的步骤中,调用构造函数之前就已经为对象赋值了原型,因此可以在父类中使用this.fn,直接检测对应的fn方法有没有在子类中实现
类的混入
即C继承B继承A
然后Person继承C,这样Person上就有了CBA中混合的方法和属性
组合胜过继承,因此很多js框架抛弃了混入转向了组合模式
代理反射
代理
创建代理
new Proxy(targetObj,handerObj)
可撤销的代理
const {proxy, revoke} = new Proxy.revocable(targetObj, handler)
返回对象中的proxy就是代理对象,执行revoke之后就把原始对象和代理对象中断了联系
撤销是不可逆的行为,revoke之后,再次对proxy对象操作会报错
代理可以继续代理代理
行程多层次的代理结构
对创建出来的代理对象的操作都能反映到目标对象上,但代理对象和目标对象不是同一个对象,他们在代码执行中的this不同,并由此可能引发问题
代理日期对象,虽然能返回proxy对象,但不能执行任何方法,执行就报错
反射
Reflect
它定义了js的13个基础操作,这些操作大多数在Object上都有对应操作
这13个基础操作也是代理可以使用的13个捕获器
反射不仅可以使用在代理的捕获器中,单独使用也可以
反射API的返回值,大多是布尔值,表示意图是否操作成功,这是判断操作成功与否的更好办法,比try\catch好
反射代替操作符
Relect.apply可以更安全的调用函数,因为apply可能被重写
代理和反射的关系
所有代理捕获器都有相应的参数,使用这些参数可以重建捕获方法的原始行为
这些原始行为js已经为我们准备好了,就是Reflect中的13个方法
捕获器不变式
捕获器可以改变所有的基本方法的行为,但是有限制,这些限制就叫做捕获器不变式
例如目标对象有一个不可配置且不可写的数据属性,那么捕获器返回一个与该属性不同的值时会报错
其他不变式自行搜索查询
捕获器与反射的13个方法
get
set
deleteProperty
defineProperty
has
getOwnPropertyDescriptor
ownKeys
getPrototypeOf
setPrototypeOf
isExtensible
preventExtensions
construct
apply
代理可以做到
跟踪属性访问
属性什么时候被访问都可以在get中获取
隐藏属性
有一些属性不想被访问,只要在get中判断key,如果不想被取值,直接返回undefine
属性验证
给属性赋值触发set,只要检查value是否符合要求就可以做到
函数与构造函数参数验证
apply和construc分别监听函数调用和构造函数new操作,能够拿到参数,再判断参数是否符合要求
数据绑定与可观察对象
对象创建时监听construct,可以把新建好的对象直接使用
对象设置值的时候,可以触发事件等
函数
创建函数
函数声明
函数声明会在任何代码执行之前读取声明,并在上下文中生成函数定义
函数表达式
只有执行到对应的表达式,上下文中才有对应的函数
箭头函数
Function构造函数
不推荐,因为字符串被解释两遍,1是作为作为常规解释代码2,是作为传给构造函数的字符串
箭头函数
箭头函数不能使用arguments
不能使用new.target
不能作为构造函数
箭头函数没有prototype属性
函数的本质
函数是一个对象
函数的名称是一个指针,指向函数
因此可以把一个函数名称复制给多个变量,他们都是一个函数
函数参数
函数不会预先检查函数声明时的参数类型和个数
因为没有验证签名机制所以也就没有函数重载
参数个数、类型不影响函数调用,未传的参数都是undefined
argumens是一个类数组对象,但不是Array的实例,它反映了所有输入参数
argumrnt和函数参数名称同步,但和参数名称不是同一个内存,只是有同步机制
可以通过arguments判断参数输入模拟函数重载
箭头函数没有arguments,但可以使用参数收集定义重载
箭头函数没有arguments对象
默认参数
使用=号可以添加默认参数
默认参数也可以是函数的返回值,但要注意作为默认参数的函数只会在函数调用,且没有传对应参数的情况下才会调用
参数作用域
参数相当于在函数体内部顶部按顺序赋值
参数是按顺序初始化的,所有后面的参数可以引用前面的参数
参数存在于自己的作用域中,不能引用函数体的作用域
参数扩展和收集
使用...可以把数组扩展到参数
给函数参数传入...params
函数声明和函数表达式
函数声明会在代码执行之前被读取,并添加到上下文中
函数表达式只有执行到对应行,才会有对应的函数
函数是一等公民
可以作为参数传递
可以作为返回值
可以赋值给变量
函数内部属性
arguments
arguments.callee
arguments对象所有函数的指针
递归防止函数改名后报错
new.target
函数作为构造函数使用时,返回被调用的构造函数
作为普通函数调用。返回undefined
this
普通函数的this指向调用它的对象
不同函数可以使用call、apply来指定调用对象,即this
apply第一个参数是this,第二个参数是参数数组或arguments实例
call第一个参数是this,其他参数是擦混敌给函数的参数
箭头函数的this,是定义时的上下文
caller
函数名.caller
引用的时调用当前函数的函数
函数属性和方法
函数名.length
命名参数的个数
函数.prototype
函数原型
其中的constructor就是函数本身
apply
call
bind
使用bind参数作为调用者(上下文)生成一个新函数
一次性绑定,不会执行,也不能再次更换this(再次apply、call、bind都不能再次替换)
bind不仅能够绑定this, 还能按照参数顺序绑定前n个参数
递归
使用arguments.callee可以使递归和函数名解耦
命名函数表达式
尾调用优化
函数内部调用函数的过程
function outerFunction(){
return innerFunction()
}
return innerFunction()
}
1.遇到外层函数体,第一个栈帧被推到栈上
2.执行到renturn,需要先计算innerFunc
3.执行到innerFunc的函数体,把第二个栈帧推到栈上
4.innerFunc返回结果
5.值返回outerFunc,再从outerFunc返回
6.栈帧弹出栈
优化后的过程
1.遇到外层函数体,第一个栈帧被推到栈上
2.执行到renturn,需要先计算innerFunc
3.引擎发现innerFunc的执行不依赖外部变量,且innerFunc的返回就是outerFunc的返回,那么直接把outerFunc的栈帧弹出也没有问题
4.弹出outerFunc的栈帧
5.执行到innerFunc的函数体,栈帧推到栈上
6.计算innerFunc,返回值
7.弹出innerFunc的栈帧
尾调优化的条件
严格模式下执行
非严格模式下,函数有argument.callee,fn.caller方法,会调用外层函数,因此外层函数的作用域不能释放
外部函数的返回值是内部函数的调用
尾调用函数返回后不需要执行额外的逻辑
为调用函数不是引用外部函数作用域中自由变量的闭包
闭包
闭包就是引用了另一个作用域中变量的函数
外部参数被一个函数所引用,如果函数不被释放,那么这个参数所在的上下文也不会被释放
内存泄露
闭包引起内存泄露
ie9之前,引用元素,元素再引用元素或元素的属性,会导致循环引用
而且ie9之前元素使用引用计数方式回收内存,导致泄露
包装私有变量
1.构造函数
2.静态私有变量
3.模块模式
使用字面量单例模式集合闭包封装私有变量
也可以不使用字面量,改用一个类的实例,也能对类的实例进行扩展
异步编程
以往的异步
以回调的形式写异步,如果异步中还有异步操作就会变成回调地狱,难以维护
promise
promise状态机
pending
resolved、fulfiled
rejected
状态一旦落定就是不可改变的、不可逆的
状态是不能被js检测的,不能被外部代码修改的,这是为了避免以同步方式处理promise
promise实例化
new Promise((resolve, reject)=>{})
promise内部的函数叫做执行器函数
初始化promise的异步行为
控制promise状态的最终转换
执行器函数是同步执行的,因为这是一个初始化程序
Promise.resolve()
实例化一个已经解决的promise
可以吧任何值都转成promise
这是一个幂等方法
Promise.reject()
实例化一个拒绝的promise,并抛出一个异步错误
异步错误不能被try,catch捕获,只能通过拒绝处理程序捕获
trycatch是同步代码,异步错误会在同步代码执行完再执行,所以捕获不到
实例方法
.then
两个参数:onResolve和onReject,当promise进入解决或拒绝时分别进入两个处理函数中‘’
不管是解决还是拒绝,函数的返回值都会被Promise.resolve包装成promise返回
.catch
给promie添加拒绝处理程序
.finally
在决绝和解决状态都会执行,但finally无法知道状态是解决还是拒绝
没有返回值时,表现为父期约的传递
返回待定期约或抛出错误、返回拒绝期约,则返回相应的期约
以上方法由于都返回一个promise,所以都可以链式调用
由于promise可以有任意多个处理程序,所以他链式调用可以构建有向非循环图的结构,也就是二叉树
.all
所有promise都解决后再解决
解决值是所有期约解决值的数组
有一个拒绝则.all拒绝,拒绝理由就是第一个拒绝理由
.race
一组期约中最先解决或拒绝的期约镜像
进度监控
promise取消
1.reject
2.race
async
为了解决利用异步结构组织代码的问题
async用于声明异步函数
异步函数的返回会被Promise.resolve包装成promise对象
异步函数始终返回promise对象
await
异步函数不会马上完成任务,需要一种暂停和恢复执行的能力
await可以暂停异步函数代码执行,等待promise解决
必须在async函数中使用
停止会恢复执行顺序
例子1
例子2
异步函数使用
1.实现sleep
闭包
var add=function(x){
var sum = 1;
var fun=function(x){
sum = sum+x
return fun
}
fun.toString=function(){
return sum
}
return fun
}
alert(add(1)(2)(3))
console.log(add(1)(2)(3))
var sum = 1;
var fun=function(x){
sum = sum+x
return fun
}
fun.toString=function(){
return sum
}
return fun
}
alert(add(1)(2)(3))
console.log(add(1)(2)(3))
答案
动态生成4*4表格,每个表格都有坐标(0,0)->(3,3),点击格子增加本格子的点击次数,
且每个格子不互相干扰,次数通过弹窗显示
且每个格子不互相干扰,次数通过弹窗显示
使用原生的call模拟实现bind
BOM
window对象
表示浏览器实例
网页中定义的所有对象、变量、函数都以window作为其global对象
通过var声明的所有全局变量和函数都会成为window对象的属性和方法
窗口
top
最上层窗口
parent
父窗口
self
window本身
opener
哪个窗口打开了此窗口
screenLeft
窗口距离屏幕左侧的位置
screenTop
窗口距离屏幕顶部的位置
moveTo(x,y)
窗口移动到坐标
y以浏览器而定可能被禁用
moveBy(x,y)
窗口移动x、y距离
像素比
css像素参考像素是像素密度为 96dpi 且与阅读器的距离为一臂长的设备上一个像素的视角。 因此,对于 28 英寸的标称臂长,视角约为 0.0213 度。
窗口大小
innerWidth
innerHeight
outerWidth
outerHeight
窗口位置
scrollX/pageXoffset
文档相对于视口滚动距离纵轴
scrollY/pageYoffset
scrollBy(x,y)
xy轴上滚动距离
scrollTo(x,y)
滚动到xy坐标
打开窗口
window.open(URL,name,specs,replace)
打开的url
目标窗口名称
会在这个窗口打开这个url
_self
_parent
_top
_blank
特性字符串
新窗口的配置,比如最大化、宽、高、是否显示状态栏、工具栏等
新打开的窗口是否在浏览器历史记录中替代当前加载页面
返回新窗口的window对象,可以基于此对象操作新窗口的大小、位置
定时器
const timeoutId = seTimeout
多少毫秒以后把任务添加到任务队列之中
如果队列中没有任务就立即执行,如果有任务会在已有任务完成之后再执行,因此毫秒数是不准的
clearTimeout(timeoutId)
const intervalId = setInterval
每个xx毫秒执行一次代码
clearInterval(intervalId)
系统对话框
alert
提示信息
alert、confirm、prompt都是同步模态框
confirm
确认信息
prompt
带有提示输入框的弹出窗口
find
查找对话框
我在浏览器没成功调用过find
print
打印对话框
同步模态框
他们在显示的时候,代码会停止执行,在他们消失之后代码才会回复执行
Location对象
location对象既是window的属性也是document的属性
window.location == location
document.location==location
hash
#号后面的散列值
host
f服务器名+端口号
hostname
服务器名
port
端口号
href
完整的url
search
查询参数,以?号开头
protocol
协议通常是http或https
pathname
路径
origin
url的源地址
查询字符串
查询字符串带有?的字符串,难以直接利用,需要做转换
URlSearchParams
接受一个查询字符串作为构造函数参数
new 出来的对象暴露了get、set、delete,toString方法,能够方便的操作查询字符串
操作地址
assign(url)
立即启用导航到url
window.location = url
会执行和assign(url)同样的操作
location.href = url
会执行和assign(url)同样的操作,修改href是最常用的
以上修改方法也能用于修改hash、search等属性,修改后都会在浏览器历史记录中增加相应的记录,并且页面会重新加载
reload
重新加载页面
replace
新页面替换当前页面,不会增加浏览器历史记录,也就无法回档之前的页面(回退按钮灰了)
Navigator
cookieEnabled
是否开启cookie
deviceMemory
Gb单位的内存容量
hardwareConcurrency
cpu核心数量
language
浏览器主语言
languages
浏览器偏好语言数组
onLine
是否联网
platform
系统平台
plugins
安装的插件
userAgent
用户代理字符串
可以用来确定浏览器类型和版本
检测插件
ie10之后,以及其他浏览器
都可以使用plugins数组中,对象的name属性检查插件名字
ie10之前,只能使用ActiveXObject(pluginId),实例化一个ActiveXObject能否成功来判断有没有安装对应插件
注意ActiveXObject类在10之后就没有了,其他浏览器也没有,所以可以先检测名称,再检测ActiveXObject是否报错
注册处理程序
registerProtocolHandler(协议, url, appname)
为某个协议类型注册一个固定处理的应用程序
例如navigator.registerProtocolHander('mailto', 'xxxxurl', 'app name')
为mailto协议注册一个处理程序,邮件可以通过指定的url打开
screen
屏幕显示器的信息
像素宽
像素高
颜色位数
等
history
当前窗口首次使用以来的用户导航历史记录
为了安全考虑,他不会暴露具体的url,但它可以在不知道实际url的基础上进行前进和后退
go(num)
num>0前进num页
num<0后退num页
back(num)
后退num页
forward(num)
前进num页
length
当前历史记录中有多少个页面
pushState
把状态信息推送到历史记录中,浏览器修改url,但页面不会重绘,不会向服务器发送请求
第一个参数应该包含初始化页面状态所必须的信息
replaceState
替换当前页面,不会产生新的记录,只会覆盖当前记录
DOM
Node类型
ELEMENT_NODE
1
标签,HTMLElement,继承了Element
nodeName==tagName
元素名称
getAttribute
setAttribute
removeAttribute
document.createElement
创建元素
ATTRIBUTE_NODE
2
元素数据类型
TEXT_NODE
3
文本节点
nodeVlaue
文本
data
文本与nodeValue相同
appendData
向节点末尾添加文本
deleteData(offset, count)
从offset删除count个字符
insertData(offset, text)
在offset位置插入text
replaceData(offset, count, text)
用text替换从位置offset到offset+count的文本
splitText(offset)
在offset位置把当前文本拆分成两个
substringData(offset, count)
提取从offset到offset+count的文本
document.createTextNode
CDATA_SECTION_NODE
4
xml中的CDATA区块
ENTITY_REFERENCE_NODE
ENTITY_NODE
PROCESSION_INSTRUCTION_NODE
COMMENT_NODE
8
注释类型
DOCUMENT_NODE
9
文档节点类型,文档对象是HTMLDocument实例(HTMLDocument继承Document)表示整个HTML页面
documentElement
表示HTML节点
body
表示body元素
doctype
文档类型
title
URL
页面url
domain
可以设置,但只能放松不能收紧
例如子域名为p2p.wrox.com,可以设置为wrox. com
referrer
连接到当前页面的那个页面的url
anchors
文档中所有带有name的a元素
forms
所有form元素
images
所有img元素
links
所有带有href的a元素
DOCUMENT_TYPE_NODE
10
文档类型节<!DOCTYPE HTML>
DOCUMENT_FRAGMENT_NODE
11
没有对应元素,他相当于一个元素仓库
把多个元素插入文档时,一个一个插入导致页面重绘,那么可以先把元素放入fragment中,再把fragment放入document中
document.createDocumentFragment
NOTATION_NODE
节点关系
childNodes
类数组对象
item(index)
每个node对象都有
parentNode
previousSibling
nextSibling
length
firstNode
lastNode
hasChildNodes
ownerDocument
节点操作
appendChild
insertBefore(newNode, targetNode)
把newNode插入到targetNode前面
由父节点调用次方法
replaceChild(newNode, targetNode)
要插入的节点和要替换的节点
removeChild
cloneNode(boolean)
是否深复制,整个节点和其整个子dom树
normalize
处理文档子树中的文本节点,
发现空文本节点则删除,如果两个同胞节点是相邻的,则合并为一个文本节点
节点定位
document.getElemetnById
getElementByTagName
MutationObserver
在Dom被修改后可以异步的执行回调,使用它可以观察整个文档或者Dom树的一部分,还可以观察属性、子节点、文本或任意组合变化
基本用法
创建observer
const observer = new MutationObserver(callback)
callback接受一个MutationRecord实例的数组,包含实例发生了什么变化,哪一部分收到了影响
observer.observe(node, options)
使用实例化出来的observer来观察某个node节点,根绝options来确定观察那些属性
observer.disconnect()
这个方法可以终止执行回调,observer对元素是弱引用,不会妨碍垃圾回收
会停止观察的所有目标
不会结束observer的生命,可以重新使用observer.observe()来关联到新的目标节点
MutationRecord
连续修改会生成多个MutationRecord,下次执行回调就会收到包含所有这些实例的数组,顺序就是变化时间发生的顺序
target
被修改影响的目标节点
type
表示变化的类型,attributes,characterData、childList
oldValue
attributeName
被修改的属性名称
attributeNamespace
addedNodes
childList类型的变化,返回变化中添加节点的NodeList
removeNodes
childList类型的变化,返回删除的节点NodeList
previousSibling
childList类型的变化,返回变化节点的前一个节点
nextSibling
childList类型的变化,返回变化节点的后一个节点
MutationObserverInit
控制对目标节点的观察范围,必须有一个是attribute、characterData、childList必须有一个是true
subtree
布尔值,是否观察目标节点的子节点,默认为false
attributes
布尔值,是否观察目标节点的属性变化,默认为false
attributeFilter
字符串数组,表示要观察那些属性
为true会把attributes也置成true
attributeOldValue
布尔值,表示MutationRecord是否记录变化之前的属性值,默认为false
为true会把attributes也置成true
characterData
布尔值,表示修改字符数据是否触发变化事件,默认为false
characterDataOldValue
布尔值,表示MutationRecord是否记录变化之前的字符数据,默认为false
为true会把characterData也置成true
childList
布尔值,表示修改目标节点的子节点是否触发变化事件,默认为false
observer.takeRecords
情况mutationRecord记录队列,并返回其中手游的MutationRecord
性能、内存与垃圾回收
MutationObserver与目标节点之间的引用关系
MutationObserver拥有对要观察对象的弱引用,不会妨碍垃圾回收机制回收目标节点
目标节点拥有对MutationObserver的强引用,目标节点从dom中被移除,随后被垃圾回收,则关联的MutationObserver也会被垃圾回收
MutationRecord的引用
记录队列中的每个MutationRecord实例至少包含对已有节点的一个引用,如果是childList类型则会包含多个节点的引用
记录队列和回调函数默认行为是耗尽这个队列,处理每个MutationRecord,然后让它们超出作用域并被垃圾回收
有时候需要保存MutationRecord,如果保存这些实例,那么也就保存了这些引用的节点,因此会妨碍垃圾回收这些节点(注意是MutationRecord而非MutationObserver)。最好的办法是,记录某些有用信息然后排期MutationRecord
节点查询
querySelector
querySelectorAll
matches
元素是否匹配选择符
getElementByClassName
元素遍历
childElementCount
子元素数量
firstElementChild
第一个Element类型的子元素
lastElementChild
最后一个Element类型的子元素
previousElementSibling
前一个Element类型的同胞
nextElementSibling
后一个Element类型的同胞
css类扩展
getElementsByClassName
classList
add
向类名列表中添加字符串
contains
判断指定的字符串是否存在
remove
删除制定的字符串
toggle
如果类名列表中已经存在制定的value就删除,不存在则添加
焦点管理
document.activeElement
保护眼当前拥有焦点的DOM元素
HTMLDocument扩展
readyState
loading
文档正在加载
complete
文档加载完成
compatMode
CSS1Compat
标准模式渲染
BackCompat
混杂模式渲染
head
指向head元素,与body对应
自定义数据属性
data-前缀标识自定义属性
插入标记
innerHTML
返回元素所有后代的HTML字符串
赋值会覆盖所有子元素
outerHTML
返回元素本身和元素后代的的字符串
赋值会覆盖本身以及后代元素
insertAdjacentHTML(index,text)
把text或html字符串插入的index
index有以下值
beforebegin
这里的begin和after指的是当前元素的开始标记和结束标记的之前或之后
afterbegin
beforeend
afterend
inertAdjacentText
同上
scrollIntoView(alignToTop或者scrollIntoViewOption)
alignToTop
布尔值,true窗口滚动后元素的顶部与视口顶部对齐
布尔值,tfalse窗口滚动后元素的底部与视口底部对齐
scrollIntoViewOptions
behavior
动画smooth、auto
block
定义垂直方向的对齐start,center,end,nearest
inline
水平方向对齐,start,center,end,nearest
未被标准化的专有扩展
children
只包含Element类型的子节点
contains
判断一个元素是否是另一个元素的后代
compareDocumentPosition
确定节点关系
innerText
返回后代文本节点
赋值会覆盖子节点
outerText
返回后代文本节点
赋值会覆盖本身及其子节点
样式相关API
style
元素对象具有style属性,能够返回行内样式
直接赋值能够更改行内样式
cssText
包含style属性的中的css代码
length
css属性数量
getPropertyPriority(propertyName)
如果属性使用了!important返回important
getPropertyValue(propertyname)
返回属性propertyName的字符串值
removeProperty(propertyName)
删除css属性
setProperty(propertyName, value, Priority)
设置css属性
计算样式
由于样式会互相覆盖,因此提供一个api返回计算完全之后的生效样式
document.defautView.getComputedStyle(Element, 伪元素字符串)
样式表
document.styleSheets
返回link或style元素定义的演示表
只读属性,不可覆盖
返回CssRuleList
Css规则CSSRule
表示样式表中的一条规则
cssText
返回整条规则的文本
parentRule
如果规则被其他规则包含,指向包含规则
parentStyleSheet
包含当前规则的样式表
selectorText
选择符
style
type
规则类型,始终为1
创建规则
使用styleSheets中的某个sheet
sheet.insertRule("body {background-color:silver}", 0)
把规则插入到第一条
删除规则
sheet.deleteRule(index)
删除第index条规则
元素尺寸
偏移尺寸
offsetHeight
元素在垂直方向上占用的像素尺寸,包括他的高度、水平滚动条的高度、上下边框的高度
offsetLeft
元素做边框外侧距离包含元素左边框内侧的像素数
offsetLeft和offsetTop是相对于包含元素的,包含元素保存在offsetParent中
offsetTop
元素上边框外侧距离包含元素上边框内侧的像素数
offsetWidth
元素在水平方向上占用的像素尺寸
客户端尺寸
clientWidth
包含元素内容及其内边距所占用的宽度
有滚动条时,是视口的宽度,没有滚动条时和scrollWIdth一致
clientHeight
元素内部空间,不含滚动条空间、不含border、不含margin
滚动尺寸
scrollHeight
没有滚动条时元素内容总高度
在没有滚动条时与clientHeight一致,有滚动条时,他是实际高度
scrollLeft
内容左侧隐藏的像素数
修改这个属性可以改变滚动条位置
scrollTop
内容顶部隐藏的像素数
修改这个属性可以改变滚动条位置
scrollWidth
没有滚动条时元素内容总宽度
确定元素尺寸
getBoundClientRect()
返回DOMRECT对象
left
元素左侧距离视口的像素
top
元素顶部距离视口的像素
right
元素右侧距离左侧视口的距离
bottom
元素下侧距离视口顶部的距离
width
height
DOM遍历
NodeIterator
document.createNodeIterator(root, WhatToSHow, filter, entityRefrenceExpansion )
root
作为遍历根节点的节点
WhatToShow
数值代码,表示应该访问哪些节点
NodeFilter.SHOW_ALL
所有节点
NodeFilter.SHOW_ELEMENT
元素节点
NodeFilter.SHOW_ATTRIBUTE
属性节点,DOM实际上用不到
NodeFilter.SHOW_TEXT
文本节点
NodeFilter.SHOW_COMMENT
注释节点
NodeFilter.SHOW_DOCUMENT
文档节点
NodeFilter.SHOW_DOCUMENT_TYPE
文档类型节点
NodeFilter.SHOW_CDATA_SECTION
CData区块节点,以下均不是html用的
NodeFilter,SHOW_ENTITY
实体节点
Nodefilter.SHOW_ORICESSING_INSERUCTION
处理指令节点
NodeFilter.SHOW_DOCUMENT_FRAGMENT
文档片段节点
NodeFilter.SHOW_NOTATION
记号节点
filter
一个NodeFilter对象或者过滤函数
NodeFilter对象需要实现一个acceptNode(node){ return NodeFilter.FILTER_ACCEPT}
返回NodeFilter.FILTER_ACCEPT表示应该访问
NodeFilter.FILTER_SKIP表示跳过访问
过滤函数需要实现一个函数,接受node参数,返回NodeFilter.FILTER_ACCEPT或者NodeFilter.FILTER_SKIP
entityRefrenceExpansion
布尔值,表示是否扩展实体引用,html中没有效果,可以穿false
createNodeIterator返回一个iterator,它含有2个方法
nextNode
下一个节点
previousNode
上一个节点
深度优先遍历
TreeWalker
document.createTreeWalker(root, WhatToShow, filter, entityRefrenceExpansion)
createTreeWalker返回一个treeIterator,他包含5个方法
parenNode
当前节点的父节点
firstChild
当前节点的第一个子节点
lastChild
当前节点的最后一个子节点
nextSibling
当前节点的下一个节点
previousSibling
当前节点的上一个节点
他与document.createNodeIterator的不同之处在于TreeWalter可以通过api进行漫游,不只是可以下一个上一个还可以直接访问子节点或父节点
深度优先遍历
Range
const range = document.createRange()
startContainer
范围起点所在的节点,选区中第一个节点的父节点
startOffset
范围起点在startContainer中的偏移量。如果startContainer是文本几点,那么startOffset表示跳过的字符数,否则表示范围中第一个节点的索引
endContainer
范围终点所在的节点,选区最后一个节点的父节点
endOffset
范围终点在endContainer中的偏移量。和startOffset的含义相同
commonAncestorContainer
以startContainer和endContainer为后代的最深节点,即他们共有的最接近的祖先节点
简单选择
range.selectNode()
选择节点及其子节点
setStartBefore(refNode)
范围起点调整到refNode之前
setStartAfter(refNode)
范围起点调整到refNode之后
setEndBefore(refNode)
范围终点调整到refNode之前
setEndAfter(refNode)
范围终点调整到refNode之后
range.selectNodeContents()
选择节点的子节点
调整范围同上
复杂选择
range.setStart(refNode, offset)
范围开始是refNode的offset个节点
range.setEnd(refNode, offset)
范围结束是refNode的第offset个节点
这种方法可以跨节点进行选择,也就是可以只包含一些元素的结束标签或某些元素的开始标签
在发现选区中缺少一个开始标签/结束标签时,会在后台动态补上这个标签
操作
range.deleteContents
从文档中删除选区,由于后台会补充缺失的标签,所以期DOM结构还完好的
rang.extractContents
从文档中删除选区,它会额外返回已经删除的文档片段,然后可以对选取进行额外操作,例如插入到别的位置
range.insertNode
在范围开始的地方插入html
range.surroundContents
使用参数中的html包含选区
range.collapse(boolean)
折叠,即范围中不包含任何节点
true,折叠到起点
false,折叠刀终点
range.collapsed()
是否折叠
选择范围之后判断是否折叠,可判断两个节点是否相邻
range.compareBoundaryPoints(range,option)
range
参与判断的另一个范围
option可以是以下值
Range.START_TO_START
比较两个起点
Range.STATRT_TO_END
比较第一个范围的起点和第二个范围的终点
Range.END_TO_END
比较第两个范围的终点
Range.END_TO_START
比较第一个范围的终点和第二个方位的起点
返回-1, 0 , 1
第一个在第二个之前返回-1
边界相同返回0
第一个边界在第二个之后返回1
range.cloneRange()
复制范围
range.detach()
解除范围对文档的引用
range.detach()
range = null
这两步是最合理的结束使用范围的方式
事件
事件冒泡
从最具体的元素开始触发,然后向上传播到文档
事件捕获
从不具体的节点出发,最具体的节点最后接受到事件
实际是为了在事件到达实际的目标元素前拦截事件
DOM事件流
事件捕获
最先发生
为提前拦截事件提供了可能
到达目标
事件冒泡
定义事件
在html上以属性的形式添加能够执行的js代码
其中的html语法字符需要转义,例如"" < > &
this指向元素
把函数赋值给DOM元素的一个事件处理程序属性
this指向元素
addEventListener(eventName, func, boolean)
参数:事件名,事件处理函数,在什么阶段调用处理程序,true,表示在捕获阶段调用,false(默认值)表示在冒泡阶段调用
大多数时候使用默认值在冒泡阶段调用,因为跨浏览器兼容性好,需要拦截就改为true,在捕获阶段调用
removeEventListener()
以同样的参数删除程序处理程序
event对象通用属性
bubbles
事件是否冒泡
cancelable
是否可以取消事件默认行为
currentTarget
当前事件处理程序所在的元素
defaultPrevented
true表示已经调用preventDefault()方法
detail
其他相关信息
eventPhase
调用事件处理程序的阶段1代表捕获阶段2代表到达目标3代表冒泡阶段
preventDefault()
取消事件默认行为,只有cancelable为true才能调用
stopImmediatePropagation()
取消后续事件的捕获和冒泡,并阻止调用任何后续处理程序
一个事件可能有多个事件处理程序,这个方法会阻止剩余的其他时间处理程序的执行
stopPropagation()
用于取消后续事件捕获或事件冒泡,只有bubbles为true才能调用
target
事件目标
trusted
true表示事件由浏览器生成,false表示事件由js代码创建
type
事件类型
view
与事件相关的抽象视图,等于事件发生的window对象
用户界面事件
DOMActivate
被鼠标或键盘激活
废弃,不要使用
load
页面加载完成
图片加载完成,img元素可以触发这个事件表示图片加载完成
unload
页面完全卸载
可以在页面完全卸载后清理一下内存,放置内存泄漏
abort
页面加载完成前被用户提前终止
error
js报错
select
文本框被选贼一个或多个字符
resize
window被缩放
使用时防止多次触发导致的过多计算
scroll
滚动带有滚动条的元素时,在元素上触发
焦点事件
blur
元素失去焦点,不冒泡
focus
获得焦点,不冒泡
focusin
元素获得焦点,focus的冒泡版
focusout
元素失去焦点,blur的冒泡版本
鼠标事件
click
鼠标单机或者键盘回车触发
dbclick
双击触发
mousedown
按下任意鼠标键触发
mouseenter
鼠标从元素外部移到元素内部触发,不冒泡,鼠标经过后代元素不触发
mouseleave
鼠标从元素内部移动到外部触发,不冒泡,经过后代元素不触发
mousemove
广光标在元素上移动时反复出发
mouseout
从一个元素移动到另一个元素触发,移动到的元素可以是原始元素的外部元素, 也可以是原始元素的子元素
mouseover
把鼠标从元素外部移动到元素内部触发
mouseup
释放鼠标键触发
触发顺序
mouseDown
mouseUp
click
mousedown
mouseup
click
dblclick
客户端坐标
clientX
clientY
页面坐标
pageX
pageY
屏幕坐标
screenX
screenY
修饰键
shiftKey
shift按下时为true
altKey
alt按下时为true
altKey
alt按下时为true
metaKey
meta按下时为true
mac上的commond键,window上的 windows键
相关元素
relatedTarget
mouseover
主要目标是获得光标的元素
相关元素是失去光标的元素
mouseout
主要目标是失去光标的元素
相关元素是获得光标的元素
鼠标按键
event上的button属性
表示按下的是哪个键
0
主键
1
中键
2
副键
滚轮事件
mousewheel
event属性wheeldata
+120
向前滚动
-120
向后滚动
键盘事件
keydown
按下键盘触发,持续按住持续触发
keypress
按下键并产生字符时触发,持续按住重复触发,更推荐textInput
keyup
释放按键触发
textInput
文本插入到文本框之前触发
与keypress的区别
textInput只在可编辑区域上触发,keypress在可获得焦点的元素触发
textInput在有新字符插入时触发,keypress对任何可能影响文本的按键触发(包括退格键)
键码keyCode
event对象保存一个keyCode叫做键码
对于数字和字母,keyCode的值与小写字母和数字的ASCII一致
字符码charCode
对于可以产生字符的按键,会有一个charCode
keypress事件发生时,能影响屏幕上文本的按键
值就是对应按键的键码,不是字符的为0
键码和字符码
key
字符键,值是文本字符(如m,1)
非字符时是键名(如Shift)
char
字符键时是ASCII码
非字符键是null
HTML事件
contextmenu
显示上下文菜单的事件
window上是右击,mac上是ctrl+单击
beforeUnload
页面卸载之前触发,可以用来阻止页面被卸载
DOMContentLoaded
DOM数构建完成时触发,不会等待图片、就是脚本、css文件的加载
readystateChange
提供文档或元素的加载状态信息
uninitialized
尚未初始化
loading
正在加载数据
loaded
加载完数据
interactive
可以教会,但尚未加载完成
complete
对象加载完成
pageHide、pageShow
firefox和opera提供的一个往返缓存功能,可以记住页面前进后退的状态,基本上是记住了整个页面
pageShow
页面显示时触发,无论是否来自往返缓存
event上存在persisted属性,true表示来自往返缓存
pageHide
页面卸载后,在unload之前触发,无论是否来自往返缓存
event上存在persisted属性,true表示来自往返缓存
hashchange
在url散列值变化时触发
设备事件
orientationchange
window.orientation
注意是window上的属性不是event上的
0
垂直模式
90
左转水平模式,主屏幕键在右侧
-90
右转水平模式,主屏幕键在左侧
deviceorientation
坐标系
x轴,从设备左侧到右侧
y轴,从设备底部到上部
z轴,从设备背面到正面
event上的属性
alpha
围绕z轴旋转时,y轴的度数
beta
围绕x轴旋转时,z轴的度数
gamma
围绕y轴旋转时,z轴的度数
absolute
表示设备是否返回绝对值
compassCalibrated
表示设备的指南针是否正确校准
devicemotion
提示设备正在移动,而不是仅仅改变了朝向
event属性
acceleration
包含xyz属性,反应不考虑重力情况下各个维度的加速信息
accelerationIncludingGravity
包含xyz属性,反应各个维度的加速信息,包含z轴自然重力加速
interval
毫秒,距离下次触发devicemotion事件的时间
ratationRate
包含alpha、beta、gamma表示设备朝向
触摸事件
touchstart
一个手指放在屏幕上
touchmove
手指在屏幕上滑动
touchend
手指从屏幕上离开
touchcancel
系统特定值跟踪触摸
event上的属性
clientX
clientY
视口坐标
pageX
pageY
页面坐标
screenX
screenY
屏幕坐标
target
事件的目标
touches
当前屏幕上 的每个触点
targetTouches
特定于事件目标的触点
changedTouches
自上次用户动作之后变化的触点
手势事件
gesturestart
一个手指已经在屏幕上,另一个手指放到屏幕上时触发
gesturechange
任何一个手指在屏幕上位置发生变化触发
gestureend
其中一个手指离开屏幕时触发
内存与性能
页面中事件处理程序的数量与页面整体性能直接相关
每个函数都是一个对象,都占用内存空间,对象越多性能越差
事件委托
事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件
动画和canvas
一般屏幕的刷新频率为60hz,即1秒刷新60次
实现平滑动画的重绘间隔为1000毫秒/60=16.6,约等于17毫秒
setTimeout和setInterval
能够实现动画
不能保证时间精度,他们只是把回调任务在n毫秒之后放入任务队列,不能保证执行时间
const id = requestAnimationFrame(callback(timestamp))
参数是一个回调函数,回调函数接受一个时间戳作为参数,说明被调用的时刻
最大的优势是由系统来决定回调函数的执行时机,重绘、刷新之前自动调用这个回调方法,因此不用制定执行时间
若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
优化:面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的requestAnimationFrame也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了CPU开销。
函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。一个刷新间隔内函数执行多次时没有意义的,因为显示器每16.7ms刷新一次,多次绘制并不会在屏幕上体现出来。
cancleAnimationFrame(ID)
通过id取消重绘任务
canvas
canvas标签
<canvas width='500px' height='500px'></canvas>
注意宽高不能用css来定义
初始化画布
第一步,获取canvas标签
const element = document.getElementById('xx');当然也可以用其他方法
第二步获取上下文
const ctx = element.getContext('2d')
矩形
ctx.fillRect(x,y,w,h)
填充矩形
strokeRect(x,y,w,h)
描边矩形
clearRect(x,y,w,h)
清理矩形
路径
开始建立路径
ctx.beginPath()
向路径集合中添加子路径
moveTo(x,y)
设置起点,如果两次路径中间没有重新moveTo,那么两次路径会被连接到一起,设置了moveTo,那么就是两个单独的路径
closePath()
闭合路径。结束的点位会链接到开始的点,形成闭合图形,这个方法不一定要执行,需要闭合就调用
lineTo(x,y)
直线
arc(x,y,半径,开始弧度,结束弧度,方向)
画圆弧
开始弧度是从x轴正方向开始,默认方向是顺时针
arcTo(x1,y1,x2,y2,半径)
切线圆弧
从起点到x1,y1,再到x2y2的一个折线上,正好是半径r圆的切线
绘制的线就是从起点到两个切点之间的线
产生的线是红色线,折线直角处是x1,y1, 蓝色线最下方是x2,y2(不是红线与蓝线交界处)
quadraticCurveTo(cpx1,cpy1,x,y)
二次贝塞尔曲线
从起点画到终点x,y,控制点是cpx1,cpy1
bezierCurveTo(cpx1,cpy1, cpx2,cpy2,x,y)
三次贝塞尔曲线
从起点画到终点x,y,控制点是cpx1,cpy1和cpx2,cpy2两个控制点
TODO:贝塞尔曲线相关知识点
rect(x,y,w,h)
矩形
显示路径
troke()
fill()
样式设置
strokeStyle
描边样式
fillStyle
填充样式
font
文字样式
'bold 15px arial'
textBaseline
文字基线
alphabetic
字母基线
top
hanging
悬挂基线对齐
middle
居中
ideographic
表意基线对齐
bottom
textAlign
文字对齐方式
start
start和end的意思是根据html元素的dir属性(ltr从左到右,rtl从右向左)来定义对齐方式,start就是开始的方向
end
left
right
center
lineWidth
线宽
lineCap
线条端点形状
butt平头
round圆头
square出方头
lineJoin
线条交点形状
round圆转
bevel取平
miter出尖
文本
fillText(text, x, y ,maxWidth)
如果文字宽度大于maxWidth,那么文字会压缩以适应最大宽度
strokText(text, x, y, maxWIdth)
文字周围会有一个描边
measureText(text)
获取text文字的信息,例如宽度
状态管理
save()
保存上下文对象的属性,比如描边颜色、填充颜色,线宽,线条样式,线条交叉样式等
可以save多次,然后restore会一次回退到相应的状态
restore()
变换
rotate(angle)
围绕原点图像选择angle弧度
scale(scalex.scaleY)
缩放,x乘scalex,y周乘scley
translate(x,y)
设置原点坐标
transform(m1_1,m1_2,m2_1,m2_2,dx,dy)
setTransform(m1_1,m1_2,m2_1,m2_2,dx,dy)
图像绘制
drawImage(image, x, y, width,height)
把一个图片绘制到x,y坐标上,并缩放成对应的widht,height
drawImage(img, imgX,imgY, imgW,imgH, canvasX,canvasY,canvasW,canvasH)
9个参数的重载
截取img图片从imgX,imgY坐标开始imgW宽imgH高的区域
放置到画布的canvasX,canvasY位置,canvasW宽,canvasH高的区域中
获取图像,canvas可以直接导出图片
toDataUrl(type,qulity)
导图图片类型,例如img/png
图片质量
阴影
shadowColor
阴影颜色
shadowOffsetX
阴影x坐标偏移量
shadowOffsetY
阴影y坐标偏移量
shadowBlur
阴影模糊量,默认为0,表示不模糊
渐变
const gradient = createLinerarGradient(x1,y2,x2,y2)
线性渐变
从x1,y1到x2,y2的渐变
需要吧gradient赋值给fillStyle或者strokeStyle来应用
注意渐变的坐标和绘制的图形坐标需要配合,否则可能只能显示一部分渐变,或完全不显示
gradient.addColorStop(range, color)
制定渐变色标
range,是0~1之间的值,表示什么位置,0是第一种颜色,1是最后一个颜色
color是颜色
const gradient = createRadialGrandient(x1,y1,r1,x2,y2,r2)
径向渐变
参数是两个圆心的坐标和半径
同样使用addColorStop来添加颜色指标
同样注意渐变的坐标需要和图形的坐标配合
图像数据
getImageData(x,y,w,h)
坐标以及宽度和高度
可以获取一个ImageData实例,包含width,height,data三个属性,其中data是图像原始像素信息的数组
每个像素在data中都由4个值表示,分别代表红绿蓝以及透明度,换句话说,第一个像素的信息包含在第0到第3个值中
灰阶过滤器
合成
globalAlpha
所有绘制内容的透明度,默认为0
globalCompositeOperation
控制图像相交时的行为
source-over
默认值,新图形在原有图形上面
source-in
新图形只绘制与原有图形重叠的部分,画布上其余部分全部透明
source-out
新图形只绘制与原有图形不重叠的部分,其余部分全部透明
source-atop
只绘制出与原有图形重叠的部分,其余图形不受影响
destination-over
新图形在原有图形下面,重叠部分只有原图形透明像素下的部分可见
destination-in
新图形在原有图形下面,画布只剩下重叠部分,其余部分完全透明
destination-out
新图形与原有图形重叠部分完全透明,原图形其余部分不受影响
destination-atop
新图形在原有图形下面,原有图形与新图形不重叠部分完全透明
lighter
新图形与原有图形重叠部分像素值相加,使该部分变亮
copy
新图形奖完全擦除并取代原有图形
xor
新图形与原有图形重叠部分的像素执行异或运算
TODO:点击canvas上的图形时,如何判断点中了(点击位置是否在某些图形中)
TODO:canvas手写扇形图
表单
提交表单
form.submit
表单重复提交
表单提交之后禁止提交按钮
通过onSbumit事件处理程序取消之后的表单提交
重置表单
form.reset
表单字段
form.elements
获取表单中的字段集合
form.elements[index]
使用索引获取字段
form.elements[name]
使用name获取字段
form[name]
表单字段属性
disabled
form
指针,指向表单字段所属的表单,这个属性是只读的
readonly
tabIndex
数值,表示这个字段在按tab时的切换顺序
type
value
表单字段方法
focus
表单元素有一个autofocus属性,可以自动为带有该属性的元素设置焦点<imput type='text' autofocus>
blur
字段公共事件
blur
change
focus
文本框
input
size
文本框宽度
maxlength
最多输入多少个字符
textarea
cols
文本宽度
初始值需要放在标签中间作为子元素
选择文本
element.select
选择所有文本
element.setSelectRange(startIndex, endIndex)
选择部分文本
select事件
取得选中文本
element.selectionStart
element.selectionEnd
输入过滤
屏蔽字符
keypress事件结合event.preventDefault()
注意屏蔽时可能屏蔽掉赋值粘贴和设计ctrl键的其他功能,所以需要判断event.ctrlKey是否为true
剪贴板
beforecopy
before事件在safari、chrome、firefox中只会在显示文本框上下文菜单时触发,ie会在copy等事件之前触发
copy
beforecut
cut
beforepaste
paste
剪贴板数据
window.clipboardData
IE
event.clipboardData
其他,只会在剪贴板事件期间访问剪贴板
剪贴板方法
clipboardData.getData('type')
clipboardData.setData(type, value)
表单验证
required
input,textarea,select带有required属性,当它为true时必填
type='email'
type='url'
parttern="\d+"
输入必须符合正则
element.checkValidity()
验证字段是否有效,如果再表单上使用可以验证整个表单的所有值是否有效
element.validity
对象,返回一些列属性,表示字段哪些规则不匹配,或者完全匹配
customError
如果设置了setCustomValidity()就返回true,否则返回false
patternMismatch
不匹配制定的正则返回true
rangeOverflow
如果字段值大于max返回true
rangeUnderflow
如果值小于min返回true
stepMisMatch
如果字段与min,max,step的值不符合返回true
tooLong
字段长度唱过maxlength返回true
typeMismatch
如果字段不是email或url要求的格式返回true
valid
如果其他属性都是false,则返回true,表示验证有效、通过
valueMissing
如果必填但没有值返回true
禁用验证
表单上添加noValidate
禁用验证
提交按钮上添加formnovalidate
通过该按钮无需验证即可提交表单
选择框编程
HTMLSelectElement有以下公共方法和属性
add(newOption, relOption)
z在relOption之前添加新的option
multiple
是否多选
options
控件所有option元素的HTMLCollection
remove(index)
移除给定位置的选项
selectedIndex
选中项基于0的索引
size
选择框中可见的行数
value
如果没有选中项,则值时空字符串
如果有一个选中项,且其value属性有值,那么选择框的值就是选中项value属性的值,即使value属性的值时空字符串也是如此
如果有一个选中项,且其value没有制定值,则选择框的值是该项的文本内容
如果有多个选项,则选择框根绝前两条规则取得第一个选中项的值
option
选项由HTMLOptionElement对象表示,属性有
index
选项在options集合中的索引
label
选项的标签
selected
是否选中,把他设置成true,会选中该项
text
选项文本
value
选项的值
富文本编辑
在HTML中嵌入一个iframe,并把designMode属性设置为on
任何元素指定contenteditable为true、
与富文本交互(此api已经被废弃,在一些浏览器还可以使用,但可能呗删除所以不要使用)
document.execCommand(command, false, value)
在文档上执行既定的命令
第一个参数是命令
第二个参数是否为命令提供用户界面的布尔值,由于filefox浏览器为true时报错,为了兼容性始终为false
value:命令需要的参数
backcolor
bold
createlink
cut
delete
fontname
fontsize
forecolor
formatblock
indent
outdent
inserthorizontalrule
insertimage
insertorderedlist
insertparagraph
insertunorderedlist
italic
justifycenter
justifyleft
paste
removeformat
selectall
underline
unlink
错误处理
try/catch
catch的error对象含有message属性,表示错误信息
其他属性根据浏览器不同有不同的字段
finally
始终运行
如果finally中有return,那么try和catch块中的return语句不会执行(这里的不会执行指的是return本身不会执行,但它后面的语句还是会执行)
错误类型
Error
基础类型,其他错误类型继承自Error
InternalError
js引擎内部错误,例如递归过深
EvalError
不把eval当成函数调用就报告这个类型的错误
例如new eval() eval = 1,这两个例子中IE、frieFox可能抛出TypeError
RangeError
数值越界
例如new Array(-10)
ReferenceError
找不到对象时发生
例如访问不存在的对象
SyntaxError
语法错误
TypeError
变量不是预期类型
例如new 10
var s = '1234'; s()
URIError
使用encodeURI和decodeURI时参数错误
例如decodeURI('%')
通过instanceof来判断错误类型
throw
抛出错误
模拟浏览器内置类型
const error = new TypeError(message)
throw error
自定义错误类型
自定义错误类型有助于在捕获错误时更准确的区分错误
捕获错误是为了组织浏览器以默认方式响应
抛出错误是为错误提供有关发生原因的说明
error事件
任务没有被try/catch处理的错误,都会触发window上的error事件
window.onerror=(message, url, line)=>{console.log(message, url, line)}
参数
错误信息
发生错误的url
行数
返回false可以阻止浏览器报告错误的行为
记录错误到服务器
记录web端产生的错误到服务器是必要的
可以实现一个logError 方法来发送错误到服务器
方法接受两个参数分别是严重成都和错误信息
使用img请求而不用ajax的原因在于
1.ajax都是使用库来封装,库本身也有可能出错
2.img不受跨域限制
3.所有浏览器都支持img,有些不支持XMLHttpRequest
调试技术
console
console.log
console.info
console.error
console.warn
console.table(array)
把符合类型数据(数组、对象)打印成table
console.clear()
情况console控制台
console.assert(表达式,message)
表达式为false,打印message
console.group(name)
console打印分组,使用groupEnd(name)结束分组
console.groupEnd(name)
console.count(p)
执行次数
console.time(name)
开始计时器
console.timeEnd(name)
结束计时器,并打印name计时器花费的时间
console.trace()
这个打印所在函数的调用过程(调用栈)
console.profile(name)
开始性能分析
chrome自带性能分析,可以在⋮ - >更多工具 - > JavaScript Profiler中查看报告
console.profileEnd(name)
结束名称为name的性能分析,分析name开始到name结束期间的性能
$0
使用节点选择器(windwos:ctrl+shift+c),选择一个节点后,该节点在控制台上可以使用$0打印出来,方便调试
debugger
JSON
一种数据格式,表示结构化数据
与js对象字面量不同点
key必须使用双引号包围,不能省略引号,也不能用单引号
没有分号的结束符
解析与序列化
JSON对象
JSON.parse(string, fn)
string转js值
fn
一个函数function(key, index){ return value}
表示如何还原json
JSON.stringfy(json,filter, indent)
js值转字符串
规则
会略过值为undefined的属性
会略过函数成员
会略过原型成员
filter
可以是数组
返回的结果只会包含该数组中列出的对象属性
可以是函数function(key,value){return value}
根据key来对value做操作,返回value会作为key的值,返回undefined会忽略该属性
indent
字符缩进
最大缩进为10
当indent是字符串时,就会使用这个字符串作为缩进,也是最大缩进为10,长度大于10的字符串会被截取
toJSON
JSON.stringfy会调用对象的toJSON方法
箭头函数作为toJSON方法时,需要注意this指向
stringfy的流程
如果可以获取实际的值则调用toJSON()方法获取实际的值,否则使用默认的序列化
如果提供的第二个参数,则应用过滤,传入过滤函数的值就是第一步返回的值
第二步返回的每个值都会相应的进行序列化
如果提供了第三个参数,则相应的进行缩进
XML
可扩展标记语言,用来存储和传输结构化数据
DOMPaser
const parser = new DomParser()
const xmldom = parser.parseFromString(string, 'text/xml')
const anotherChild = xmldom.createElement('child')
xmldom.documentElement.appendChild(anotherChild)
XMLSerializer
const serializer = new XMLSerilizer()
const xmlString = serializer.serializeToString(xmldom)
XPath
一种在xml中查找信息的语言
Path 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
选取节点
/
bookstore/book
选取属于 bookstore 的子元素的所有 book 元素。
//
//book
选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book
选取bookstore的所有 后代book 子元素,而不管它们在后代中的位置。
..
选取当前节点父节点
@
选取属性
//@lang
选取名为 lang 的所有属性。
谓语,放在中括号中用于选取特定元素
bookstoer/book[0]
bookstore子元素中的第一个book元素
last()
last()-n
position()<3
前n个元素
@xxx
拥有属性名为xxx的元素
@name=value
拥有属性名为name属性值为value的元素
xmlname>num
元素名为xmlname的值大于num
通配符
*
任何元素节点
@*
任何属性节点
node()
任何类型节点
运算符
a|b
a和b节点
XSL
XSL 指扩展样式表语言(EXtensible Stylesheet Language)。
XSL 可描述如何来显示 XML 文档!
XSL 包括三部分:
XSLT - 一种用于转换 XML 文档的语言。
XPath - 一种用于在 XML 文档中导航的语言。
XSL-FO - 一种用于格式化 XML 文档的语言。
XSLT - 一种用于转换 XML 文档的语言。
XPath - 一种用于在 XML 文档中导航的语言。
XSL-FO - 一种用于格式化 XML 文档的语言。
XSLT
XSLT 是 XSL 中最重要的部分。
XSLT 用于将一种 XML 文档转换为另外一种 XML 文档
XSLT 用于将一种 XML 文档转换为另外一种 XML 文档
XSLT 使用 XPath 来定义源文档中可匹配一个或多个预定义模板的部分。一旦匹配被找到,XSLT 就会把源文档的匹配部分转换为结果文档。
https://www.runoob.com/xsl/xsl-transformation.html
浏览器对XPath的支持
xmldom.evaluate(expression, context, nsresolver, type, result)
expression
XPath表达式
context
上下文节点
nsresolver
命名空间解析器,当xml有命名空间时才有必要
type
返回结果类型
XPathResult.ANY_TYPE
适合XPath的任何类型
XPathResult.NUMBER_TYPE
数值
XPathResult.STRING_TYPE
字符串
XPathResult.BOOLEAN_TYPE
布尔值
XPathResult.UNORDERED_NODE_ITERATOR_TYPE
返回匹配节点集合,集合中节点顺序可能和文档中不一致
XPathResult.ORDERED_NODE_ITERATOT_TYPE
返回匹配节点集合,集合中节点顺序和文档中顺序一致
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE
返回节点集合快照,对文档的修改不会影响这个节点集合,且不保证顺序
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
返回节点集合快照,对文档的修改不会影响这个节点集合,可以保证顺序和文档一致
XPathResult.ANY_UNORDERED_NODE_TYPE
返回匹配节点集合,顺序可能不一致
XPathResult.FIRST_ORDERED_NODE_TYPE
返回只有一个节点的节点集合,包含的是文档中第一个匹配的节点
result
XPathResult对象
返回值
如有有结果返回一个XPathResult对象,没有结果返回null
如果结果是一个集合,那么XpathResult上有一个iteratorNext方法,用来获取集合中的下一个元素,直到返回null
XPathResult结果获取
result.singleNodeValue
XPath.First_ORDERED_NODE_TYPE使用该方法取返回值
result.booleanValue
XPath.BOOLEAN_TYPE类型的返回值使用 它来获取返回值,表示expression是否有节点匹配
result.numberValue
表示XPath匹配了多少个节点
result.stringValue
表示匹配的第一个节点其第一个子节点的值
命名空间
evaluate方法的第二个参数,如果xml文档中有命名空间定义,那么这个参数需要一个XPathNSResolver对象
xml.createNSResolver(namespaceElement)
把定义了命名空间的节点传给createNSResolver方法,可以获取命名空间解析器
吧命名空间解析器传递给evaluate方法就能正确解析带命名空间前缀的XPath表达式
对XSLT的支持
XSLTProcessor
用于根据xsl文件装换xml
const processor = new XSLTProcessor()
processor.importStyleSheet(xsltdom)
导入xslt文档
processor.transformToDocument(xlmdom)
吧xml根据xslt装换成完整的文档,然后返回
processor.transformToFrogment(xmldom, newDoucument)
得到文档片段,并插入到一个新文档中
设置参数
processor.setParameter(Uri, key, value)
设置参数,Uri一般是null
重置处理器
processor.reset()
reset方法可以删除所有参数和样式表,然后就可以使用imprtStyleSheet重新加载新的样式表
网络请求
XMLHttpRequest
使用ajax(asynchromous JavaScript + XML)
注意xhr只能同源发送,即域名、端口、协议都相同
const xhr = new XMLHttpRequest()
初始化xhr对象
xhr.open(method, url, boolean)
打开,请求类型、地址、是否异步
xhr.send(data)
发送数据
xhr.abort()
收到响应前可以使用abort方法取消异步请求
xhr数据完成的检测
readyState
0
uninitialized, 未初始化,未open
1
open, 调用了open方法未send
2
sent, 调用了send方法,未响应
3
receiving, 接受中已经收到部分响应
4
complete,收到所有响应
onreadyStateChange
当readyState状态发生变化就会触发onreadyStateChange事件,如果readyState值为4,那么表示数据已经就绪
数据发送之后,xhr对象的以下属性会被填充
responseText
响应体文本
responseXML
如果返回内容类型是‘text/xml’或者'application/xml'那么就是包含相应数据的xml文档
status
http状态
2xx
成功
304
从缓存读取,资源未修改过
5xx
服务器错误
statusText
http状态描述
header
Accept
浏览器可以处理的内容类型
Accept-Charset
浏览器可以显示的字符集
Accept-Encoding
浏览器可以处理的压缩编码类型
Accpet-Language
浏览器使用的语言
Connection
浏览器与服务器的连接类型
Cookie
页面中设置的Cookie
Host
发送请求的页面所在的域
Referer
发送请求的页面的URI
User-Agent
用户代理字符串
设置头部
xhr.setRequestHeader(key,value)
获取已经设置的header
xhr.getResponseHeader(name)
xhr.getAllResponseHeader()
Get请求
xhr.open('get', url)
POST请求
xhr.open('post', url)
FormData
便于表单序列化
const data = new FormData()
初始化
data.append(key, value)
添加数据
xhr.send(data)
使用ajax发送数据
超时
xhr.timeout
超时,发送请求后等待多少毫秒,如果请求不成功就中断请求
xhr.ontimeout
请求超时后的事件
进度事件
loadStart
接受到响应的第一个字节时触发
progress
接受响应期间反复触发
event对象
target
XHR对象
lengthComputable
布尔值,表示进度信息是否可用
position
接收到的字节数
totalSize
总字节数
error
请求出错触发
abort
终止链接触发
load
成功接受万响应触发
loadend
童心完成时,在error,abort或load之后触发
跨域
xhr只能访问与发请求的页面在同一个于内的资源
域名、协议、端口有一个不同就是跨域
发送请求的头部会有一个Origin字段,包含了发送请求的页面的源(协议、域名、端口)
如果服务器决定相应请求,那么发送Access-Control-Allow-Origin头部,包含相同的源,或者值是‘*’表示任何源可访问
如果这个头部与请求的Origin不匹配就不会相应浏览器请求
预检请求
CORS通过预检请求的服务器验证机制,允许使用自定义头部、除Get、POST之外的方法、以及不同请求体内容类型
涉及上述高级请求时,会先发送一个预检请求,这个预检请求使用OPTIONS方法发送,头部如下
Origin
Access-Control-Request-Method
希望使用的方法
Access-Control-Request-Headers
要是用的逗号分隔的自定义头部列表
在请求发送之后,服务器可以确定是否允许这种类型的请求,服务器会在响应中发送以下头部来与浏览器沟通
Access-Control-Allow-Origin
允许的源
Access-control-Allow-Method
允许的方法,逗号分隔的列表
Access-Control-Allow-Headers
服务器允许的头部,逗号分隔的列表
Access-Control-Allow-Max-Age
缓存预检请求的秒数
结果可以缓存一段时间,时间之内不用再发送额外的OPTIONS请求
凭据请求
默认情况下,跨域请求不提供凭据(cookie、http认证,客户端SSl证书),可以通过奖withCredentials设置为true来表明会发送凭据
服务器可以在相应头部中包含Access-Control-Allow-Credentials:true
替代性跨域技术
图片探测
利用任何页面都可以跨域加载图片,不同担心跨域限制的特点来发送跨域请求的技术
创建一个Img实例,把他的src替换成要发送的GET请求
通过img的onload和onerror方法就可以判断请求的成功或失败
注意:这种方法是单向通信、不能接收返回值拿不到任何数据,只能发送GET请求,常常用于跟踪用户在页面上的点击操作或动态显示广告
JSONP
动态创建<script>并为src属性指定跨域url实现的,原理和img一样,script元素能够不受限制的从其他域加载资源
缺点
从不同域拉去代码执行,可能会有恶意内容
不好确定JSONP请求是否失败,script元素的onerror事件并未被所有浏览器实现,所以经常需要写计时器来决定是否放弃等待
fetch API
fetch()方法暴露在全局作用域中,包括主页面件执行线程、模块、工作线程
基本用法
const r = fetch(url, options)
返回一个promise
r.then(response=>{})
请求完成promise会resolve一个Response对象,并可以通过这个对象来获取返回数据
注意:不管请求是否成功(状态是500、300、200)都会走resolve处理函数
超时、服务器不响应请求则会走reject处理函数,(违反cors的跨域、无网络链接等)
options选项
定义了如何发送请求
body
请求体内容,必须是Blob、BufferSource、FormData、URLSearchParams、ReadableStream、String的实例
method
请求方法,Get、POST、PUT、PATCH、DELETE、HEAD、OPTIONS、CONNECT、TARCE
默认为GET,没有options时也是get
credentials
omit
不发送cookie
same-origin
同源发送cookie,默认值
include
无论同源还是跨域都发送cookie
heads
请求头,Heads对象实例或者包含字符串格式键值对的普通对象
keepalive
允许请求存在的时间超过页面生命周期
mode
请求模式
cors
允许遵守CORS协议的跨域请求
no-cors
允许不需要发送预检请求的跨域请求
same-origin
任何跨域请求都不允许发送
redirect
follow
跟踪重定向请求,以最终重定向url的相应作为最终相应
error
重定向抛出错误
manual
不跟踪重定向,返回响应中暴露重定向的url,允许手动处理
cache
缓存交互
Default
返回命中的有效缓存,不发送请求
命中无效缓存发送条件式请求,如果响应已经改变,更新缓存的值然后fetch()返回缓存的值
未命中缓存,发送请求并缓存响应,fetchI()返回响应
no-store
不检查缓存、直接发送请求
不缓存响应,直接fetch()返回
reload
不检查缓存,直接发送请求
缓存响应,通过fetch()返回
no-cache
无论命中有效缓存还是无效缓存都会发送条件式请求,如果响应已经变化则更新缓存的值,然后fetch返回缓存的值
未命中缓存,会发送请求缓存响应,fetch()返回响应
force-cache
无论命中有效缓存还是无效缓存都通过fetch()返回,不发送请求
未命中缓存会发送请求,缓存响应人后fetch()返回响应
only-if-cached
只在请求模式为same-origin时使用缓存
无论命中有效缓存还是无效缓存都通过fetch返回,不发送请求
未命中返回504
singal
AbortSignal的实例
用于中断进行中的fetch请求
const abortController = new AbortController()
创建中断请求实例
fetch(url,{singal: abortController})
请求数据
abortController.abort()
执行中断
Headers
每一个response和Resquest对象上都会对应的Headers对象,用来获取响应和请求的头部信息
Header对象和Map类似,具有get、set、delete、has方法
const header = new Headers()
初始化时和map不同,可以使用键值对对象作为初始化对象
new Header({foo:'bar'})
header.set('foo', 'bar')
header.get('foo')
header.has('foo')
true
header.append('foo', 'baz')
给foo属性添加另一个baz值,此时foo变成了"bar,baz"
header.delete('foo')
Request
const request = new Request(url, options)
参数和fetch参数相同
克隆Request
const request2 = new Request(request, options)
创建一个副本,可以使用新的options覆盖之前的设置
不一定得到一样的副本,第一个请求在克隆之后它的bodyUsed被设置成true
const request2 = request.clone()
创建一个一模一样的副本
请求的body被读取之后(request.text()等方法)bodyUsed被置成true,bodyUsed为true的request不能被克隆,此时克隆报错
注意:没有请求体的请求不受此限制
fetch( request )
被请求过的带有请求体的request对象的bodyUsed也会变成true,同样也不能再次使用
注意:没有请求体的请求不受此限制
Response
const response = new Response(body, options)
可选的body和options
options
headers
Header对象实例,或其他常规对象
status
http状态码
statusText
http响应状态字符串
Response.error()
这个静态方法生成网络错误的响应对象,可以导致fetch被拒绝
Response.redirect()
这个静态方法生成重定向响应对象,它的status必须对应重定向
response对象字段
headers
头部信息
ok
布尔值,200-299位true,其他为false
redirected
布尔值,是否经过至少一次重定向
status
http状态码
statusText
http状态码描述
type
响应类型
basic
同源响应
cors
跨域响应
error
响应通过Response.error()创建
opaque
表示no-cache返回的跨域响应
opaqueredirect
表示对redirect设置为manual的响应
url
url
克隆
const response2 = response.clone()
bodyUsed为true的响应对象不能克隆,注意没有响应体的response不受此限制
有body的响应,只能被读取一次,多次读取报错,注意没有响应体的response不受此限制
Reques、Response以及Body混入
Request和Response都使用了Fetch API的body混入,使他们可以使用body的一些属性和方法
body
只读,ReadableStream的实例
这个实例是一个流,具有getReader()方法
产生一个读取器const reader = body.getReader()
reader.read().then(console.log) ====>{value:xxxx, done:fase}
通过done判断流是否全部读取完成
bodyUsed
只读,body流是否被读取
Body.text()
返回promise,resolve为字符串
Body.json()
返回promise, resolve为JSON
Body.formData()
返回promise, resolve为FormData实例
Body.arrayBuffer()
返回promise, resolve为ArrayBuffer实例
Body.Blob()
返回promise, resolve为Blob实例
Body混入构建在ReadableStream之上的,所有犯法都只能使用一次,多次调用报错,没有body也就没有这个限制
Beacon
用于在页面关闭之后也能发送请求,多用于在页面生命周期中尽量晚的时候向服务器发送分析数据
navigator.sendBeacon(url, body)
body载荷可以是ArrayBufferView、Blob、DomString、formData实例
sendBeacon不是只能在页面生命周期末尾使用,在任何时候都可以使用
调用sendBeacon之后,浏览器会把请求添加到一个内部队列,浏览器会主动发送队列中的请求
浏览器保障原始页面关闭的情况下也会发送请求
状态码、超时和其他网络原因造成的失败是完全不透明的,不能通过编程处理
beacon请求会携带senBeacon时所有相关的cookie
WebSocket
长时链接实现与服务器全双工、双向通信
创建webSocket时,一个http请求会被发送到服务器,用来初始化链接,服务器响应之后,链接使用http的upgrade头部从http协议切换到websocket协议
websocket使用了自定义协议,因此需要使用ws://和wss://,前者是不安全链接,后者是安全链接
const socket = new WebSocket("ws://xxxxxx")
创建websocket
socket.send(data)
发送数据
socket.onmessage=function(event){}
获取服务器向客户端发送的数据,event.data
状态
WebSocket.OPENING(0)
正在建立连接
WebSocket.OPEN(1)
已经建立连接
WebSocket.CLOSING(2)
正在关闭
WebSocket.CLOSE(3)
已经关闭
onopen
连接成功触发
onerror
发生错误触发,连接无法存续
onclose
连接关闭触发
客户端存储
cookie
用于早客户端存储会话信息
服务器在响应http请求时,通过发送Set-Cookie HTTP头部包含会话信息,浏览器会存储会话信息,之后个请求都会通过http头部cookie发回服务器
限制
cookie与特定域绑定,放置被恶意利用
有空间限制
不超过300个cookie
每个cookie不超过4096个字节
超过大小静默设置删除
每个域最好不超过20个
不同的浏览器对同一个域cookie有不同的限制
IE、Edge不超过50个
fireFox不超过150个
Opera不超过180个
Safari、chrome没有硬性限制
多设置的cookie会导致之前的某一个cookie被删除,不同的浏览器有不同的策略,可能删除最少使用的、可能随机删除
每个域不超过81920字节
cookie构成
名称
表示cookie的名称,不区分大小写,但最好当成区分对待
值
字符串
名称和值都是URL编码之后的,需要使用decodeURIComponent解码
获取值
通过document.cookie获取有效cookie字符串
name1=value1;name2=value2;name3=value3
设置值
document.cookie = 'name=xxx; expires=过期时间;domain=域名; path=路径; secure'
设置值不会删除之前的cookie,除非设置了同名值
域
有效的域,发送到这个域的请求都会带上对应cookie
路径
请求url包含这个路径才会发送cookie
过期时间
何时删除cookie的时间戳,默认浏览器会话结束会删除所有cookie,除非设置删除时间,这样即使关闭浏览器也能保留cookie到指定时间
把过期时间设置为过去的时间会立即删除cookie
安全标志
设置之后,只有使用https的链接才会发送
注意
cookie是不安全的,任何人都可以获取,不要存取敏感信息
cookie存储大量数据都会发送到服务器,因此大量cookie拖累请求速度
Web Storage
Storage类型
localstorage.clear()
删除所有数据
getItem(name)
setItem(name,value)
removeItem(name)
key(index)
或者制定位置的数据
localstorage
永久存储机制
只能访问同一个域的localstorage
是Storage类型的实现,因此有Storage所有犯法
sessionStorage
跨会话存储机制,只会存储到浏览器关闭
是Storage类型的实现,因此有Storage所有犯法
存储事件
window.addEventListener('storage', (event)=>alert(event.newValue))
event有4个属性
domain
变化对应的域
oldValue
旧值
newValue
新值
key
变化对应的键
限制
大小有限制,取决于特定浏览器
同一个域 下,大多是5M
IndexedDB
方便js对象的存储和获取,也支持查询和搜索
打开数据库
const request = indexedDB.open(name, version)
打开特定名称和版本的数据库的请求
如果没有对应的名称和版本会发送一个创建一个对应的数据库的请求
request.onerror = (e)=> console.log(e)
打开失败
request.onsuccess = (e)=>db = event.target.resut
打开成功
其中的event.target.result就是数据库对象
创建对象存储
使用open创建一个数据库或修改版本后会触发upgradeennded事件,这个事件中可以更新数据库模式,也就是新建表
request.onupgradeneeded=(event)=>{const db = event.target.result; db.createObjectStore(name, options)}
createObjectStore(name,options)
name 是数据库表名称
option:{keyPath: key}指定主键
也可以使用autoIncrement:true选择自增主键
事务
const transaction = db.transaction([name1, name2], option)
可以读取name1,name2等对象存储
option 可以是readonly,readwrite,versionchange,决定了只读、读写权限
const store = transaction.objectstore(name)
获取名为name的对象存储
const request = store.get(key)
在request.onsuccess的事件对象上有值,对象存储通过key获取值
插入
store.add(object)
添加对象,如果对象key重复会报错
store.put(object)
添加对象,如果对象键重复则重写该对象
游标
const cursor = store.openCursor(range, direction)
range是键的范围,可以传null,表示所有范围
direction表示方向可以是 next,nextunique,prev,prevunique
unique类型的方向表示遇到重复记录跳过
cursor.onsuccess=(e)=>{}
event.target.result
如果有下一条记录,则是IDBCursor的实例
没有下一条记录则是null,以此判断游标是否完成遍历
IDBCursor的实例
direction
遍历方向包括NEXT、 NEXTUNIQUE、 PREV、 PREVUNIQUE
key
对象的键
value
实际的对象
primaryKey
游标使用的键,可能是对象键或索引键
键范围
单独一个键
IDBKeyRange(key)
定义结果的下限
IDBKeyRange.lowerBound(key, flag)
结果从key开始到最后
flag为true表示不包含key这一条记录
定义结果的上限
IDBKeyRange.bound(key,flag)
到键为key的记录停止
flag为true表示不包含key这一条记录
定义一个范围
IDBKeyRange.bound(lowerKey, upperKey, flag1, flag2)
结果集从lowerKey到UpperKey的记录
flag1为true表示不包含lowerKey
flag2为true表示不包含upperKey
索引
创建索引
const index = store.createIndex(name, key, option)
name
索引名称
key
在key这个字段上建立索引
option
{unique:true}
表示这个键在记录中是否重复,true为不重复,false为有可能重复
获取存储对象上已经存在的索引
const index = store.index(name)
使用索引查询
const request = index.openCursor()
在request.onsuccess的事件对象上有值,和游标的使用一样
const request=index.get(key)
在request.onsuccess的事件对象上有值,获取索引键为key的记录
const request = index.getKey(key)
在request.onsuccess的事件对象上获取返回,获取所有索引键为key的记录的主键集合
限制
不能跨域共享
有空间限制,但已经很大了,理论上甚至可以有无限大
webwork
概述
js是单线程的,webwork允许吧主线程的工作转嫁给独立的实体,而又不改变现有的单线程模型
webwork中不能使用依赖于单线程交互的api,比如DOM操作
特点
webwork是以实际线程实现的
webwork并行执行
webwor可以共享某些内存(SharedArrayBuffer),但不能公共享全部内存
webwork不一定是在同一个进程中,不同的浏览器的实现不同,可能webwork和主线程在不同进程中
创建webwork开销更大,因为有自己独立的时间循环、全局对象、事件处理、以及js运行所需要的其他环境和特性
全局对象
window中全局对象即window,在webwork中全局对象为WorkerGlobalScope,通过self暴露出来
属性
navigator
self
本身
performance
console
caches
indexedDB
isSecureContext
工作者线程上下文知否安全
origin
fetch
setTimeout
setInterval
clearTimeout
clearInterval
专用webwork
让脚本单独创建一个js线程,以执行委托的任务
只能被创建它的页面使用,且它的生命周期、代码路径、输入输出都由初始化线程时提供的脚本来控制
创建webwork
const worker = new Worker('xxx.js')
只能加载同源脚本
worker事件和方法
work.onerror
webworker内部发生错误时触发
worker.onmessage
webworker向父上下文发送消息触发
work.onmessageerror
webwooker无法反序列化消息时发生
work.postMessage()
通过异步消息事件向webWork发送信息
work.terminate()
立即终止webwork,没有为webworker提供清理的机会,脚本突然停止
self属性和方法
self.postMessage()
由webworker内部向父上下文发送消息
self.name
可以给Worker构造函数提供一个可选的字符串标识符
self.close()
与worker.terminate()对应的方法,立即终止webworker,脚本突然停止
self.importScripts()
导入任意数量的脚本
importScripts(path)
在webworker内部按顺序加载另外的脚本
导入的脚本共享作用域
意思是从webWorker内部定义的全局变量,在其他导入的脚本中也能取到
生命周期
初始化
new出一个worker,虽然此时worker已经在父上下文中存在,但worker本身的线程可能还没有创建完成
此时发送消息,会把消息加入队列,等待状态变为活动之后,再把消息加入到它的消息队列
活动
之后webworker会伴随页面的整个生命周期存在,除非使用worker.termite()或self.close()手动结束
只要工作者线程仍然存在,worker对象就不会被垃圾回收机制回收
终止
worker.termite()会直接锁定webwork的消息队列,并且进行清理,因此之后发送的消息都不会被webworker内部接收
self.close()
不会执行同步停止,它会通知webworker取消事件循环中的所有任务,并阻止新任务添加
这个地方这么理解:close方法会放到当前消息队列的最后一个,所以close之后的同步消息还是可以发送,但下一个微任务队列就不会再接受任务了
worker配置
Worker(path, option)构造函数接受可选的配置对象作为第二个参数
option
name
webworker中通过self.name取得的字符串标识符
type
module
当成模块执行
classic
常规脚本
credentials
type为module时,制定如何获取与传输凭证数据相关的工作者线程模块脚本
omit、same-orign、include
委托任务到字工作者线程
webworker内部可以再次new Worker()
子webworker也要受同源限制
MessageChannel通信
webworker与父上下文通信,除了利用postMessage和onmessage还可以利用MessageChannel
简单原理就是把MessageChannel生成的其中一个端口传到webWorker中去,再利用对应的端口来接受、发送信息
worker.js
main.js
利用messageChannel实现父页面通信是多余的,因为postMessage和MessageCHannel实现的是一个操作,MessageChannel真正有用的地方在于把两个端口传递给两个不同的webworker,实现两个工作者线程之间的直接通信
Broadcast通信
原理就是链接到同一个broadcast频道,使用这个频道来发送接收数据
worker.js
main.js
注意、由于broadcastChannel的特性,如果没有实体监听信道,对应的消息就不会被处理,而worker初始化需要时间,因此不能在new出一个worker之后立即发送数据,因为此时对应channel的监听很可能还没有产生,导致消息丢失(无人处理)
共享webwork
可以被多个不同页面使用,只要是同源的脚本都可以向共享webwork发送或接收消息
创建共享worker
const sharedWorker = new ShareWorker('xxx.js')
sharedWorker只有在相同的标识不存在时才会新建实例,否则会建立与已有的共享线程建立连接
工作者线程名称也是标识的一部分,所有不同的name会产生不同的worker线程
shareworker属性
onerror
port
与共享线程通信的MessagePort
slef属性
name
字符串标识符
importScripts()
向工作者线程导入任意数量的脚本
close()
关闭工作者线程
onconnect
建立连接时的处理程序
服务webwork
拦截、重定向、修改页面发出的请求,充当网络请求的仲裁者的角色,并且可以决定那些api可以缓存以及缓存策略
必须同源才能访问,且必须是https安全上下文中使用
创建serviceWorker
navigator.serviceWorker是ServiceWorkerContainer的实例
通过它可以管理serviceWorker
navigator.serviceWorker.register('xxx.js', options)
成功时返回promise,resolve为ServiceWorkerRegistration对象
第一次激活serviceWorker后再次在同一个页面使用相同url注册,实际上什么也不会执行,返回相同的ServiceWorkerRegistration对象
ServiceWorkerContainer对象
它可以始终咋全局作用域中通过navigator.serviceWorker访问
oncontrollerchange
在ServiceWorkerContainer获得新激活的serviceWorkerRegistration触发
onerror
相关联工作者线程抛出错误触发
onmessage
服务脚本向父上下文发送消息触发
属性
ready
返回解决为ServiceWorkerRegistration对象的期约
controller
返回与当前页面关联的激活的ServiceWorker对象
方法
register(url, option)
使用url和option创建或更新ServiceWorkerRegistration
getRegistration()
返回promise,解决为返回与提供的作用域匹配的ServiceWorkerRegistration对象
getRegistrations()
返回promise,解决为与ServiceWorkerContainer关联的ServiceWorkerRegistration对象
starMessage()
开始传送通过Client.postMessage()派发的消息
ServiceWorkerRegistration对象
事件
onupdatefound
serviceWorker开始安装新版本时触发
属性
scope
返回服务工作者线程完整的url
navigationPreload
返回与注册对象关联的NavigationPreloadManager实例
pushManager
返回与注册对象关联的pushManager实例
installing
如果有则返回为状态未installing安装 的服务工作者线程serviceWorker对象
wating
如果有返回状态未waitin 等待的服务工作者线程serviceWorker对象
active
如果有则返回装为 activation或active 活动 的服务工作者线程serviceWorker对象
方法
getNotifications()
返回promise 解决为Notification对象的数组
showNotifications()
显示通知,可以配置title和options参数
当用户关闭或点击消息时可以触发工作者线程内部self.onnotificationclick或self.onnotificationclose事件
update()
直接从服务器重新请求服务脚本,如果脚本不同则重新初始化
unregister()
取消服务工作者线程的注册,该方法会在服务工作者线程执行完再取消注册
serviceWor对象
获得
通过ServiceWorkerContainer的controller属性获得
通过ServiceWorkerRegistration的active属性获得
事件
onstateChange
ServiceWorker.state变化时触发
属性
scriptUrl
解析后户注册服务工作者线程的URl
state
返回状态
installing
installed
activating
activated
redundant(多余)
工作者线程内部的Self
ServiceWorkerGlobalScope的实例
属性
caches
返回CacheStorage对象
clients
返回Clients接口,用于方位底层Client对象
registration
安徽ServiceWorkerRegistration对象
方法
skipWaiting()
强制服务工作者线程进入活动状态,需要和Clients.claim()一起使用
fetch()
在服务工作者线程内如发送网络请求
事件
self.oninstall
服务工作者线程进入安装状态触发,这是服务工作者线程接受的第一个事件,在线程一开始执行就会触发
self.onactivate
进入激活或已激活状态触发,服务工作者线程准备好处理功能性事件和控制客户端时触发
self.onfetch
在服务工作者线程接货来自主页面的fetch请求时触发
self.onmessage
服务工作者线程通过postMessage()获取数据时触发
self.onnofiticationclick
系统告诉浏览器用户点击了ServiceWorkerRegistration.showNotification()生成的通知时触发
self.onnotificationclose
系统告诉浏览器用户关闭或取消了ServiceWorkerRegistration.showNitifocation()生成的通知时触发
self.onpush
在服务工作者线程接收到推送消息时触发
self.onpushsubscriptionchange
在应用外的因素(非js显式操作)导致推送订阅状态变化时触发
工作者线程内部访问关联的窗口Client
用于跟踪关联的窗口、工作线程或服务工作者线程,使用self.clients获得
属性
id
客户端全局唯一的标识符,可以用于通过Client.get(id) 获取客户端的引用
type
客户端类型,window、worker、sharedworker
url
客户端url
方法
postMessage()
向单个客户端发送消息
get(id)
获取客户端
matchAll(options)
options
includeUncontrolled
boolean,true时返回结果不包含当前服务工作者线程控制的客户端,默认fasle
type
string, windwo、worker、sharedworker,默认all
self.clients方法
openWindow(url)
在新窗口中打开指定URL,会给当前服务工作者线程添加一个新Client,新Client对象以promise的形式返回,可用于回应点击操作
claim()
强制性设置当前服务工作者线程以控制其作用域中的所有客户端。可用于不希望等待页面重新加载而让服务者线程开始管理页面
缓存
网页缺少缓存网络请求的稳健机制,http缓存没有对js暴露编程接口,其其行为是受js运行时外部控制的
serviceWorker缓存特定
不自动缓存任何请求,所有缓存都必须明确制定
没有到期失效的概念,除非明确删除否则缓存一直有效
缓存必须手动更新和删除
版本必须手动管理,每次服务工作者线程更新,新服务者线程负责提供新的缓存键以保存新缓存
唯一的浏览器强制逐出策略基于服务工作者线程缓存占用的空间,基于最近最少使用的原则为新缓存腾出空间
CacheStore对象
是映射到Cache对象的字符串键/值存储,api类似Map,通过self.caches属性暴露出来
const cache = self.caches
每个缓存是用过caches.open(key)取得,缓存不存在就会创建,它返回promise
caches.open('v1').then(console.log)
===>Cache{}
方法
caches.has(key)
key对应的缓存是否存在
delete(key)
删除key 对应的缓存
keys()
返回缓存中所有的key
match()
根据Request对象所搜Cache对象,注意是Cache对象
Cache对象
是CacheStore通过open 方法返回的promise的解决结果
它的键可以是url也可以是request对象,这些键会映射到response对象。默认情况下Cache不允许POST、PUT、DELETE等请求方法,因为这些方法意味着与服务器交换信息,一般情况下不适合客户端存储
方法
put(url/request, response)
以url或request为key, response为value 添加缓存,添加成功后返回promise
add(url/request)
在只有request对象或url时使用此方法发送fetch请求,并缓存响应,返回promise
addAll([url/request])
在希望填充全部缓存时使用,比如在服务者线程初始化缓存,接受url或response数组,会请求数组中的每一项分别调用add(), 返回promise,都成功后resolve
delete()
删除缓存
keys()
返回缓存的key数组
搜索方法
matchAll(request, options)
返回promise,解决为匹配缓存中response对象的数组
匹配时url和request可以互换,实际上request也是使用request对象中的url来匹配
match(request, options)
返回promise,解决为匹配缓存中response,没有返回undefined
匹配时url和request可以互换,实际上request也是使用request对象中的url来匹配
options配置搜索行为
cacheName
只有matchAll支持,只会匹配Cache键为制定字符串的缓存值
ignoreSearch
boolean, true忽略url键的查询字符串
ignoreMedth
boolean,true时忽略查询的http方法
ignoreVary
boolean, true时忽略Vary头部,该头部指定哪个请求头部导致服务器响应不同的值
如果同一个url需要根据不同的情况返回不同的数据,那么就需要一个内容协商机制,一般是用Accept(媒体类型)、Accept-Language(语言)、Accept-Charset(字符集)、Accept-Encoding(压缩形式),userAget等
如果中间有一个缓存服务器,例如serviceWorker,他就要分辨出同一个url需要返回缓存的哪种数据,这时候就需要服务端需要添加一个vary头部,来说明每一种返回的不一致性,让缓存服务器根据不同之处分别缓存,也根据不同之处返回给前端正确的数据
一致性和版本
js代码有时候会递增更新,因此在浏览器中运行的文件,必须都属于同一个版本
网页也会向localstorage或indexedDB写入数据,也会api获取数据,不同版本的格式可能有变化,所以也要保证属于同一个版本
保证一致性的手段
服务工作者线程提早失败,安装工作者线程任何预料之外的问题都可能组织安装成功,包括脚本加载失败、语法或运行时错误、设置某个缓存资源失败
服务工作者线程激进更新。浏览器再次加载脚本时哪怕一个字节不同也会启动安装新版本的服务工作者线程
未激活的服务工作者线程消极活动。当页面第一个register()时,serviceWorker会安装但不会激活,在导航事件发生前不会控制页面
活动的服务工作者线程粘连。只要至少有一个客户端与关联到活动的服务工作者线程,浏览器就会在所有页面中使用它。浏览器可以安装一个新的服务工作者线,但在与原有活动的工作者线程实例关联的客户端为0之前不会切换到新工作者线程。放置两个客户端同时运行不同版本的serviceWorker
生命周期
parsed已解析
刚通过navigator.serviceWorker.register()启动创建的serviceWorker会进入已解析状态,但改状态没有事件、没有值,永远不会返回parsed这种状态,最早的状态是installing
确保脚本来自相同的源
确保在安全上下文https中注册
确保脚本能被成功解析不报错
存储脚本快照,下次下载脚本会与这个脚本快照对比差异,决定是否更新worker
上述任务成功后进入installing状态
installing安装中
执行所有服务工作者线程设置任务的状态,包括在服务工作者线程控制页面前必须完成的操作
他会使ServiceWorkerRegistration.installing设置为serviceWorker实例,会触发使关联的serviceWorkerRegistration的updatefound事件
用于填充服务工作者线程的缓存,在成功缓存制定资源前一直处于这个状态,任何资源缓存失败都会跳至redundant状态
可以使用installEvent中的awatiUntil方法使状态一直处于这个状态,知道对应的缓存加载完毕
installed已安装
也成为了等待中awaiting,此时worker没有事情做,准备得到许可的时候去控制客户端。如果没有活动的worker,则新安装的worker会跳到这个状态,并直接进入激活中状态
可以在已安装状态通过self.skipWaiting()强制推进服务工作者线程到下一阶段,也可以提示用户重新加载,让浏览器按部就班的推进
activation激活中
服务工作者线程即将被浏览器选中成为可以控制页面的服务工作者线程。
如果浏览器中没有活动的serviceWorker,那么新serviceWorker会自动进入激活中,如果已经有一个激活状态的serviceWorker,可以使用一下方法进入激活状态
原有的serviceWorker客户端数量变成0,意味着标签页都被关闭,再次打开会使用新的serviceWorker,注意刷新最后一个客户端也不会进入activated状态,因为刷新页面期间会发生重叠,旧页面还未卸载新页面就已经加载了
已安装的serviceWorker执行self.skipWaiting()
激活中状态下不能发送请求和推送事件,他只是个预备役
activated已激活
表示serviceWorker正在控制一个或多个客户端,能够捕获fetch事件、通知和推送事件
redundant已失效
serviceWorker已经宣布死亡,不会再有事件推送给它,他随时可能被浏览器垃圾回收
更新服务工作者线程
检查更新
再次创建工作者线程但使用不同的url
浏览器导航到服务工作者线程作用域的一个页面
发生了fetch或push事件,而且至少24小时没有发生更新检查
使用ServiceWorkerRegistration.update()强制下载服务脚本
服务脚本缓存
js文件会按照cache-control头部纳入http缓存,如果工作者线程脚本被缓存,那么在缓存文件失效前都不会接受更新的服务脚本
为了尽可能更新服务脚本
1. 可以把cache-control头部的max-age设置为0,也就是即时失效
2.在register 服务工作者线程时,使用updateViaCache配置,来配置如何管理脚本缓存,但并不是所有浏览器都支持
这个配置有
imports
默认值,顶级脚本不会被缓存,但通过importScripts加载的脚本会按照cache-controll头部设置纳入http缓存
all
所有脚本没有特殊待遇,都会根据cache-contrl头部设置纳入http缓存
none
所有脚本都不会被缓存
强制性服务工作者线程操作
有时候,在安装完成之后,需要强制进入活动状态,这时为了服务工作者线程在不同客户端版本一致,需要强制服务工作者线程去控制关联的客户端
过程
1.通过installEvent.waitUntil 等待安装成功
2. 安装成功后通过self。skipWaiting()强制进入活动状态,并触发self.onactivate事件
3. 此时线程还没有关联客户端,需要强制关联客户端,使用clients.claim()
消息处理
1.服务工作者线程接受消息后,再返回给客户端消息
客户端
接收消息
navigator.serviceWorker.onmessage=data=>console.log(data)
发送消息
得到serviceWorker实例,调用postMessage(data),两种方式获取
1.ServiceWorkerRegistration.active
2.navigator.serviceWorker.controller
navigator.serviceWorker.register('xxx.js')
.then(registeration=>{
if( registration.active){
registration.active.postMessage('aaaa')
}
})
.then(registeration=>{
if( registration.active){
registration.active.postMessage('aaaa')
}
})
navigator.serviceWorker.register('xxx.js')
.then(registeration=>{
if( navigator.serviceWorker.controller){
navigator.serviceWorker.controller.postMessage('aaaa')
}
})
.then(registeration=>{
if( navigator.serviceWorker.controller){
navigator.serviceWorker.controller.postMessage('aaaa')
}
})
worker
self.onmessage = (data, source)=>{
console.log(data)
source.postMessage('aaa')
}
console.log(data)
source.postMessage('aaa')
}
先从客户端发来的事件中获取source,也就是哪个客户端发来的,再用这个客户端发回去
2.服务工作者线程主动先发送消息
主动发消息需要知道发给哪个客户端,且由于是主动发,一般是在激活之后立即发送,这时候可能客户端还不在控制之下,匹配客户端时需要加上includeUNController:true参数
客户端
navagator.serviceWorker.onmessage=(data, source)=>{
console.log(data)
source.postMessage(data)
}
console.log(data)
source.postMessage(data)
}
worker
接收消息
self.onmessage=data=>console.log(data)
发送
self.onactivate=()=>{
slef.clients.matchAll({includeUncontroller:true})
.then((clientMatches)=>clientMatches[0].postMessage('data'))
}
slef.clients.matchAll({includeUncontroller:true})
.then((clientMatches)=>clientMatches[0].postMessage('data'))
}
拦截fetch请求
可以拦截fetch请求、js、css、图片等资源
缓存策略如下
1. 从网络返回
简单转发fetch事件
self.onfetch=(fetchEvent)=>{
fetchEvent.respondWith( fetch(fetchEvent.request) )
}
fetchEvent.respondWith( fetch(fetchEvent.request) )
}
2. 从缓存返回
对于必定有缓存的资源,例如安装阶段缓存的资源
self.onfetch=(fetchEvent)=>{
fetchEvent.respondWith( caches.match(fetchEvent.request) )
}
fetchEvent.respondWith( caches.match(fetchEvent.request) )
}
3. 从网络返回,缓存作为后备
self.onfetch=(fetchEvent)=>{
fetchEvent.respondWith( fetch(fetchEvent.request)
.catch(()=>caches.match(fetchEvent.request)) )
}
fetchEvent.respondWith( fetch(fetchEvent.request)
.catch(()=>caches.match(fetchEvent.request)) )
}
以网络请求中最新的数据作为首选,如果缓存中有值也会返回缓存的值,用于离线情况下仍要展示一些信息
4. 从缓存返回,网络作为后备
self.onfetch=(fetchEvent)=>{
fetchEvent.respondWith(
caches.match(fetchEvent.request)
.then((response)=>response||fetch(fetchEvent.request))
)
}
fetchEvent.respondWith(
caches.match(fetchEvent.request)
.then((response)=>response||fetch(fetchEvent.request))
)
}
这个策略有限考虑速度,仍会在没有缓存的情况下发送网络请求
5. 通用后备
在缓存和网络都不可用的情况下,可以在安装时缓存后备资源,在都失败时返回他们
self.onfetch=(fetchEvent)=>{
fetchEvent.respondWith(
caches.match(fetchEvent.request)
.then((response)=>response||fetch(fetchEvent.request))
.catch(()=>caches.match('./fallback.html'))
)
}
fetchEvent.respondWith(
caches.match(fetchEvent.request)
.then((response)=>response||fetch(fetchEvent.request))
.catch(()=>caches.match('./fallback.html'))
)
}
通知处理
服务工作者线程能够显示通知
能够处理通知交互
能够订阅服务器发送的推送通知
能够处理推送消息,及时应用程序没在前台运行或根本没打开
1.显示通知
worker
self.onactivate=()=>self.registration.showNotification('xxxx')
客户端
需要先使用Navigator.requestPermission()获取授权
navigator.serviceWorker.register(xxx)
.then(registration=>{
Notification.requestPermission()
.then(status=>{
if(status === 'granted'){ registration.showNotification('xxxxx')}
})
})
.then(registration=>{
Notification.requestPermission()
.then(status=>{
if(status === 'granted'){ registration.showNotification('xxxxx')}
})
})
2. 处理通知事件
worker
self.onnotificationonclick=(notification)=>console.log(notification)
self.onnotificationclose=(notification)=>console.log(notification)
es6之后各版本提案特性汇总
es7
array.includes(data)
数组是否包含某个元素返回boolean
**
指数运算符
es8
async/await
异步终极方案
Object.values
返回值的数组,不包含继承的值
Object.entries
返回二维数组,[[key,value]]
string1.padStart(targetLength, string2)
使用string2在字符串1之前填充到targetLength,如果填充的字符串超过了指定长度,则截断string2
string1.padEnd(targetLength, string2)
使用string2在字符串1后面填充到targetLength,如果填充的字符串超过了指定长度,则截断string2
函数的最后一个参数后面允许写逗号
fun( a, b, c, )
这样在参数较长、每一个参数一行显示时,可以直接添加下一行的参数。在git等版本控制中,看一看到只有新增的参数有变化
之前不允许参数尾逗号时,如果新增参数,会导致Git显示最后两行都是修改状态,看上去像是修改了两个参数一样,同时也是和对象尾逗号规则一致
Object.getOwnPropertyDescriptors
返回对象自身所有属性的描述
SharedArrayBuffer
SharedArrayBuffer 对象用来表示一个通用的,固定长度的原始二进制数据缓冲区,类似于 ArrayBuffer 对象,它们都可以用来在共享内存(shared memory)上创建视图。与 ArrayBuffer 不同的是,SharedArrayBuffer 不能被分离。
new SharedArrayBuffer(length)
可以用来在worker中共享内存,可以见worker
注意:由于2018年发现的一个cpu漏洞,可以被利用进行旁路攻击,这种攻击是一种时序攻击,依赖精确的时间,所以浏览器厂商为了缓解这个问题,把performance.now()时钟精确度不同程度降低,由于sharedArrayBuffer可以构造精确时钟,因此很多厂商已经禁用了SharedArrayBuffer
Atomics 对象
提供了一组静态方法用来对 SharedArrayBuffer 对象进行原子操作。这些原子操作属于 Atomics 模块。与一般的全局对象不同,Atomics 不是构造函数,因此不能使用 new 操作符调用,也不能将其当作函数直接调用。Atomics 的所有属性和方法都是静态的(与 Math 对象一样)
多个共享内存的线程能够同时读写同一位置上的数据。原子操作会确保正在读或写的数据的值是符合预期的,即下一个原子操作一定会在上一个原子操作结束后才会开始,其操作过程不会中断。
Atomics.add(typedArray, index, value)
将制定位置上的数组元素与给定的值相加,并返回相加前改元素的值
Atomics.and(typedArray, index, value)
将给定的值与数组上的值进行按位与操作,并将结果赋值给数组,然后返回数组该位置上的旧值。
Atomics.or()
给定位置的按位或给定值, 并返回该位置的旧值
Atomics.compareExchange(typedArray, index, expectedValue, replacementValue)
数组的值与期望值相等的时候,将给定的替换值替换掉数组上的值,然后返回旧值
Atomics.exchange(typedArray, index, value)
用 给定的值替换掉数组上的值,然后返回数组的旧值
Atomics.load(typedArray, index)
返回一个数组当中给定位置的值。
Atomics.store(typedArray, index, value)
给定的值存储在数组中的指定位置,并返回该值。.
Atomics.sub(typedArray, index, value)
减去数组中给定位置的给定值,并在该位置返回旧值。
Atomics.xor(typedArray, index, value)
将指定位置上的数组元素与给定的值相异或,并返回异或操作前该元素的值。
Atomics.wait(typedArray, index, value[, timeout])
验证 Int32Array 中的给定位置是否仍包含给定值, 如果休眠, 则等待唤醒或超时。它返回一个字符串, 它可以是 “ok”、“不等于” 或 “超时”。
Atomics.wake(typedArray, index, count)
Atomics.wake()方法唤醒在等待队列中休眠的某些代理
Atomics.isLockFree(size)
可以用来检测当前系统是否支持硬件级的原子操作。对于指定大小的数组,如果当前系统支持硬件级的原子操作,则返回 true;否则就意味着对于该数组,Atomics 对象中的各原子操作都只能用锁来实现。
es9
异步迭代 await for
Promise.finally()
无论Promise运行成功还是失败,运行相同的代码
Rest/spread
增强了rest和扩展运算符
rest可以作用域对象
可以对对象进行浅拷贝
正则表达式命名捕获组
ES2018允许命名捕获组使用符号?<name>,在打开捕获括号(后立即命名
正则表达式反向断言
(?=pattern)
正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)
正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。
(?<=pattern)
反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”
(?<!pattern)
反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”
正则表达式dotAll模式
点 . 匹配除回车之外的所有单字符,标记为 s
正则表达式Unicode转义
非转义序列的模板字符串
es10
Array.flat(depth)
数组展平,参数是展开的层级,默认为1,可以传infinity展开所有
Array.flatMap()
参数是一个Array.map的回调
先执行Array.map生成新数组,再执行flat(1)深度为1的展平操作
String.trimStart()
去掉开头空格
String.trimEnd()
去掉结尾空格
String.matchAll()
返回与正则表达式匹配字符串的所有结果的迭代器,包括捕获组。
Symbol.description
symbol对象新增的一个属性description,可以返回只读的描述
Object.fromEntries()
Object.entries()的反向操作,可以把二维数组的[[key, value]]装换成对象
可选catch
catch之后紧跟的错误参数可以省略
JSON Superset超集
支持解析行分隔符(\u2028)和段落分隔符(\u2029)
JSON.stringfy()加强格式转化
'😀'.length === 2
这是因为emoji表情由2个字符串代理组合而成,但是单独的一个代理字符串没有意义
单独的一个字符串在stringfy时,之前会变成特殊字符失去含义,现在可以正确保留UTF-8/UTF-16代码
JSON.stringify('\uD83D');
// '"\\ud83d"'
Array.sort()更加稳定
之前v8在10个以上元素的数组上使用了不稳定的排序方法例如快排,现在更加稳定
可以传入排序函数,对对象数组排序
function.toString()重新修订
现在可以原样返回函数的字符串形式,包括注释也能正确返回
es11
动态import() 按需导入
es6中的导入import xx from 'xxx' 都是静态声明,无法满足一些动态导入的需求:
需要根据浏览器兼容性有选择的加载一些库
在实际需要时才加载某个模块
只是单纯的希望延迟加载某些模块来渐进渲染的方式改进加载体验
返回promise,在模块加载完成后解决,结果是一个对象,默认导出的key是default,具名导出项放在同名属性中
import('xxx').then(module=>{})
空置合并运算符 ??
??操作符避免data||1操作时,当data为0会取1的问题
只有左边的值是null或undefined才会取右边的值
可选链接 ?.
当尝试访问某个对象上的属性,又不确定对象是否存在时使用
data?.a
就算data为undefiend也不会报错
func?.()
函数不存在时返回undefiend
BigInt
js number类型使用64位浮点数存储,因此最大值为2^53-1
BigInt类型可以使用任意精度的整数
使用方式
数字后边后缀n
使用构造函数 new BigInt(1234)
支持number所支持的运算符+,-,*,/,%,**
要注意/除法结果会向下取整,因为bigInt毕竟是int类型
支持和字符串拼接
支持和number比较大小,支持装换成boolean类型,装换和number一样,0n转换成false,其他为true
转换
可以通过Number()转换成普通number类型,但有精度降低的问题
可以通过BigInt()把number转成BigInt
不支持
不支持和普通number一起运算
Math函数一些方法不支持BigInt
BigInt和number 不严格相等
1n==1 true
1n===1 false
GlobalTHis
在不同环境中全局对象并不一致,例如浏览器中是window,worker中是self,node中是global
为了在不同环境中可以取到全局对象可以使用
const globals = (new Functon('return this'))()
但由于安全策略,以及eval的安全性问题,这段代码可能无法运行
或者穷举各种全局对象是否存在
globalsThis在不同环境中就是不同的全局对象方便使用
Promise.allSettled
promise.all
所有promise都是resolved状态后该promise转成resolved状态,有一个rejectd则该promise状态为rejected
promise.race
有任意一个resolved或rejected后,该promise切换到相同的状态
promise.allSettled
当所有promise都切换成resolved或rejected之后,改promise切换到fullfilled状态
promise.any
任意一个promise切换到fullfilled状态之后,该promise切换到fulfilled状态;所有promise都是rejected状态,该promise切换到rejected状态
for-in
规范了for-in的遍历顺序
es12
string.replaceAll
模式的所有匹配都会被替换,返回新字符串
promise.any
任何一个promise完成时返回那个完成值的promise,所有promise都rejected,返回一个拒绝的promise
逻辑赋值操作符
??=
e=e??f ===> e??=f
||=
a = a||b ======> a||=b
&&=
a = a&&b ======> a&&=b
weakRef
拿到一个对象的弱引用,并且不会妨碍垃圾回收这个对象
const ref = new WearRef(anyObj)
使用ref.deref()得到引用的值
intl.ListFormat
Intl.DateTimeFormat
数字下划线分隔符
var num= 9_999_999
数字太长可读性变差,加下划线提高可读性
Node.js
React
函数式
hooks
useState
useEffect
useLayoutEffect
useRef
useReducer
useCallback
useMemo
useContext
useImperativeHandle
优化
useCallback
useMemo
React.memo
类组件
生命周期
挂载
constructor
getDerivedStateFromProps
render
componentDidMount
更新
getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
ComponentDidUpdate
卸载
componentWillUnmount
componentWillMount
废弃
componentWillReceiveProps
废弃
ComponentWillUpdate
废弃
优化
shouldComponentUpdate
继承PureComponent
包管理工具
yarn
npm
npx
自动运行模块中的可执行二进制文件
react native
原理解析
三个线程
main thread
又称UI thread 负责UI渲染、用户行为监听,APP启动首先创建的线程
javascript thread
通过jsCore或Hermes引擎运行、解析js代码
shadow thread
处理虚拟Dom Diff之后的变更操作指令
原生端和js端的交互式通过bridge进行的,bridge是给js引擎提供原生接口的api扩展供js调用
热更新
react native的产物是bundle文件,就是js代码,应用启动时会获取budnle,然后解析,这就天然允许开发者在云端更新budle
不足
原生和react native交互依赖Bridge,js和native交互是异步的,所以在大量实时交互时性能不足
什么是RN
RN 是一个使用react和应用平台的原生功能来构建Android和IOS应用的开源框架,可以使用js来方位移动平台API
RN组件就是对原生视图的封装
核心组件
<View>
<Text>
<Image>
<ScrollView>
<TextInput>
长列表
FlatList
垂直滚动列表虚拟滚动
SectionList
可分组的虚拟滚动
平台定制
Platform
Platform.OS返回ios、android
Platform.select({ios:xxxx,android:xxxx})平台自动引用相应代码
特定平台扩展名
不同平台的逻辑放在不同后缀的文件中
xxx.ios.js
xxx.android.js
注意!!! reactnative所有依赖不要使用cnpm, 他安装的模块路径比较奇怪,packager不能正常识别!!!!此处见官网
ios
安装
node
12版本+
watchman
修改文件实时更新的包
xcode
React Native 目前需要Xcode 12 或更高版本,它提供ide、模拟器等工具
注意苹果开发者不好使用国内电话,会报您的账户暂时不符合此应用的条件...用邮箱就可以
CocoaPods
iOS包管理器
android
安装
javaJDK
Android studio
混合开发优势
成本低
天然跨平台
热更新,可以通过服务器直接下发js代码,绕过审核
可扩展,可以通过原生桥的方式扩展js的原生硬件能力,且大多都是开源免费的
混合开发劣势
性能问题
权限配置
默认只允许https配置
ios配置
ios/项目名/Info.plist
NSAppTransportSecurity应用传输安全配置
其他权限可以查苹果文档
需要一个<key></key><string>xxx</string>格式配置权限,key中放置权限string中放置说明
android
android/src/debug/AndroidManifest.xml
android/src/main/AndroidManifest.xml
打包时两个配置会合并,开发环境debug/AndroidManifest.xml文件优先,生产环境main/AndroidManifest.xml优先
注意androdi:usesCleartextTraffic='true'配置可以使用http请求,它只在dev环境中,生产环境中如果也使用http请求需要加上这一行
样式
StyleSheet.create来集中定义样式
尺寸没有单位,它代表的是与设备像素密度武官的逻辑像素点,做到不同尺寸屏幕上都是一样大小
flexDirection默认为column
图片
使用Image加载图片<Image source={require('./img/check.png')} />
可以根据后缀的.ios.png和 .android.png自动加载对应图片
可以根据后缀的@2x.png、@3x.png自动为不同屏幕精度提供图片
注意:为了使新的图片资源机制正常工作,require 中的图片名字必须是一个静态字符串(不能使用变量!因为 require 是在编译时期执行,而非运行时期执行!)。
网络图片的请求参数
注意:网络图片必须手动指定尺寸,为了放置图片加载过程中上下跳动使用用户体验糟糕,本地图片是已知尺寸,所以可以不指定尺寸
背景图
<ImageBackground>
必须制定宽高
在主线程外解码图片
图片解码可能会超过一帧的时间,这是掉帧的一大因素
rn中解码是另一线程完成的
交互
触摸
onPress
TouchableHighlight用于封装识图,可以正确响应触摸操作
支持onLongPress
TouchableOpacity
TouchableWithoutFeeback
导航器
react-navigation
react-native-navigation
动画
Animated
6个可以动画化的组件
Animated.View
Animated.Text
Animated.Image
Animated.ScrollView
Animated.FlatList
Animated.SectionList
组合动画
parallel
同时执行
sequence
顺序执行
stagger
错开
delay
requestAnimationFram
接受一个函数作为唯一参数,在下一次重绘之前调用此函数
使用原生动画驱动
useNativeDriver
性能优化
console.log
大量的打印语句会拖累js线程
第三方的npm包中也可能有大量的打印,比如redux-logger
解决:
使用babel-plugin-transform-remove-console插件在编译时删除打印语句
虚拟滚动
FlatList
getItemLayout
SectionList
屏幕上移动视图(滚动,切换,旋转)
ios:shouldRasterizeIOS
预渲染一个缓存了静态视图的位图,并快速合成,由于会产生一个离屏的位图渲染过程,会产生内存损耗
android:renderToHardwareTextureAndroid
把自己和子视图渲染到GPU的硬件纹理中,大量消耗内存
动画改变图片尺寸
在IOS上修改图片尺寸都要重新剪裁和缩放原始图片,这个开销非常大
解决:使用transorm:[{scale}]的样式属性改变尺寸,比如点击图片放大到全屏
touchable组件不能很好响应
操作与点击产生的透明度改变或高亮效果中间产生掉帧,比如在onPress中执行了一个setState操作,这个操作又需要大量计算工作导致掉帧
解决:onPress封装到requestAnimationFrame中,延迟到动画结束再执行onPress
动画慢
开启原生动画驱动useNativeDriver
开发模式会慢一些
因为要有警告、错误信息、propTypes属性验证以及其他警告的产生
延迟加载模块
使用require代替import在史记需要该文件时再加载
注意清除定时器
patch-package
用于给第三方库打补丁
修改node_module中的代码后,使用 npx patch-package xxxx命令,会在patches文件夹中生成一个补丁文件
补丁文件可以上传到git分享给团队,之后所有人只要重新install npm包就会打上这个补丁
之后就算删除node_modules重新安装,patch-package也会根据补丁重新修改代码
注意项目引用的是源码还是编译后的代码,引用的是编译代码就要改编译的代码,此时很难修改(也可以使用源码重新编译、、、)
小程序
原理
逻辑层和视图渲染层分开,逻辑层运行在JSCore中,它并非一个完成的浏览器对象
小程序时图层使用webView渲染
小程序逻辑层采用ios:JSCORE android:x5内核 开发工具:chrome运行js脚本
JSBridge
微信能力
网络请求
native系统层
逻辑层修改数据后反应到视图层
1. js线程无法直接修改webView线程的DOM结构
2.js线程修改setData后,生成虚拟DOM树和数据字符串,发送到JSBridget桥
3.JsBridge桥转发数据到WebView
4. diff算法对比差异更新界面
0 条评论
下一页