CSS3+H5
[CSS3.0 帮助文档.chm](CSS3.0 帮助文档.chm)
注意:CSS3 不支持 IE6,7,8。兼容性
单位相关:px em rem
相对长度单位
px像素(Pixel)。相对长度单位,像素 px 是相对于显示器屏幕分辨率而言的。
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。
任意浏览器的默认字体高都是 16px。所有未经调整的浏览器都符合: 1em=16px。
那么 12px=0.75em,10px=0.625em。
为了简化 font-size 的换算,可以在 css 中的 body 选择器中声明 Font-size=62.5%,这就使 em 值变为 16px*62.5%=10px, 这样 12px=1.2em, 10px=1em, 也就是说只需要将你的原来的 px 数值除以 10,然后换上 em 作为单位就行了。
EM 特点
em 的值并不是固定的;
em 会继承父级元素的字体大小。
所以我们在写 CSS 的时候,需要注意两点:
body 选择器中声明 Font-size=62.5%;
将你的原来的 px 数值除以 10,然后换上 em 作为单位;
重新计算那些被放大的字体的 em 数值。避免字体大小的重复声明
也就是避免 1.2 * 1.2= 1.44 的现象。比如说你在#content 中声明了字体大小为 1.2em,那么在声明 p 的字体大小时就只能是 1em,而不是 1.2em, 因为此 em 非彼 em,它因继承#content 的字体高而变为了 1em=12px。
rem 特点
rem 是 CSS3 新增的一个相对单位(root em,根 em),这个单位引起了广泛关注。这个单位与 em 有什么区别呢?区别在于使用 rem 为元素设定字体大小时,仍然是相对大小,但相对的只是 HTML 根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。目前,除了 IE8 及更早版本外,所有浏览器均已支持 rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用 rem 设定的字体大小。下面就是
一个例子:
p {font-size:14px; font-size:.875rem;}
注意:
选择使用什么字体单位主要由你的项目来决定,如果你的用户群都使用最新版的浏览器,那推荐使用 rem,如果要考虑兼容性,那就使用 px,或者两者同时使用。
在这里为大家提供一个 px,em,rem 单位转换工具
flex 弹性布局:
<参考资料:http://www.runoob.com/w3cnote/flex-grammar.html>
**兼容性问题:**Webkit 内核的浏览器,必须加上-webkit 前缀。
1 | .box { |
注意:设为 Flex 布局以后,子元素的 float、clear 和 vertical-align 属性将失效。
1.基本概念
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称”项目”。
主轴:橫 交叉轴:竖
2.容器具有的属性
flex-direction
决定主轴的方向(项目的排列方向)
- row(默认值):主轴为水平方向,起点在左端。
- row-reverse:主轴为水平方向,起点在右端。
- column:主轴为垂直方向,起点在上沿。
- column-reverse:主轴为垂直方向,起点在下沿。
flex-wrap
定义如果一条轴线排不下,如何换行。
- nowrap(默认值) :不换行(会把项目压缩)
- wrap :换行
- wrap-reverse: 换行,第一行在下面
flex-flow
属性和 flex-wrap 属性的简写形式
1 | .box { |
justify-content
项目在主轴上的对齐方式。
- flex-start(默认值):左对齐
- flex-end:右对齐
- center: 居中
- space-between:两端对齐,项目之间的间隔都相等。
- space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
align-items
定义项目在交叉轴上如何对齐
- flex-start:交叉轴的起点对齐。
- flex-end:交叉轴的终点对齐。
- center:交叉轴的中点对齐。
- baseline: 项目的第一行文字的基线对齐。
- stretch(默认值):如果项目未设置高度或设为 auto,将占满整个容器的高度。
align-conten
定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
3.项目具有的属性****
order:定义项目的排列顺序。数值越小,排列越靠前,默认为 0。
flex-grow:定义项目的放大比例,默认为 0,即如果存在剩余空间,也不放大。
flex-shrink:定义了项目的缩小比例,默认为 1,即如果空间不足,该项目将缩小。
flex-basis:
定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为 auto,即项目的本来大小。
设为跟 width 或 height 属性一样的值(比如 350px),则项目将占据固定空间。
flex:flex-grow, flex-shrink 和 flex-basis 的简写,默认值为 0 1 auto。后两个属性可选。
align-self:允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性。默认值为auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretc
该属性可取 6 个值,除了 auto,其他都与 align-items 属性完全一致。
1
2
3.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
transtion:过渡
语法格式:
1 | transition: 要过渡的属性 花费时间 运动曲线 何时开始; |
属性 | 描述 | CSS |
---|---|---|
transition | 简写属性,用于在一个属性中设置四个过渡属性。 | 3 |
transition-property | 规定应用过渡的 CSS 属性的名称。 | 3 |
transition-duration | 定义过渡效果花费的时间。默认是 0。 | 3 |
transition-timing-function | 规定过渡效果的时间曲线。默认是 “ease”。 | 3 |
transition-delay | 规定过渡效果何时开始。默认是 0。 | 3 |
1 | img { |
响应式开发相关
布局方式:固定宽度布局 流式布局栅 格化布局 响应式布局(主流)
响应式布局:缺点。代码冗余,性能拥挤,但是开发效率高
适用于官网博客,新闻资讯等内容性网站
@media 媒体查询
针对不同媒体类型(或者说屏幕宽度)自适应采用不同的样式规则。当你重置浏览器大小的过程中,页面会根据浏览器的宽度和高度重新渲染页面。
用于响应式布局,根据设备屏幕不同
常用区间值
超小屏幕 | (移动设备)xs | w<768px |
---|---|---|
小屏设备(平板)sm | 768px-992px | 768<=w<992 |
中等屏幕(电脑 1024)md | 992px-1200px | 992=<w<1200 |
宽屏设备lg | 1200px 以上 | w>=1200 |
使用 @media 查询,你可以针对不同的媒体类型定义不同的样式。
@media 可以针对不同的屏幕尺寸设置不同的样式,特别是如果你需要设置设计响应式的页面,@media 是非常有用的。
当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面
向上兼容:如果设置了小的,小的会传递到大的
向下覆盖:宽度大的覆盖前面宽度更小的
书写顺序建议
如果判断最小值:从小到大写
如果判断最大值:从大到小写
- 媒体查询的基本实现方式:常用属性设置: http://www.runoob.com/cssref/css3-pr-mediaquery.html
a) CSS 语法
1 | @media mediatype and|not|only (media feature) { |
1、and 可以将多个媒体特性连接到一起,相当于“且”的意思。
2、not 排除某个媒体类型,相当于“非”的意思,可以省略。
3、only 指定某个特定的媒体类型,可以省略。
1 | <!--你也可以针对不同的媒体使用不同 stylesheets : --> |
b) 媒体类型
值 | 描述 |
---|---|
all | 用于所有设备 |
用于打印机和打印预览 | |
screen | 用于电脑屏幕,平板电脑,智能手机等。 |
speech | 应用于屏幕阅读器等发声设备 |
c) 媒体功能
值 | 描述 |
---|---|
device-width | 定义输出设备的屏幕可见宽度。 |
max-device-height | 定义输出设备的屏幕可见的最大高度。 |
max-device-width | 定义输出设备的屏幕最大可见宽度。 |
min-device-width | 定义输出设备的屏幕最小可见宽度。 |
min-device-height | 定义输出设备的屏幕的最小可见高度。 |
max-height | 定义输出设备中的页面最大可见区域高度。 |
max-width | 定义输出设备中的页面最大可见区域宽度。 |
min-height | 定义输出设备中的页面最小可见区域高度。 |
min-width | 定义输出设备中的页面最小可见区域宽度。 |
device-height | 描述定义输出设备的屏幕可见高度。 |
bootstrap 框架(针对 bootstrap3)
- col- 针对所有设备
- .col-sm- 平板 - 屏幕宽度等于或大于 576px
- .col-md- 桌面显示器 - 屏幕宽度等于或大于 768px)
- .col-lg- 大桌面显示器 - 屏幕宽度等于或大于 992px)
- .col-xl- 超大桌面显示器 - 屏幕宽度等于或大于 1200px)
boostrap 是 向上兼容的
栅格原理(col-xs-12):
- “行(row)”必须包含在
.container
(固定宽度)或.container-fluid
(100% 宽度)中,以便为其赋予合适的排列(aligment)和内补(padding)。 - 通过“行(row)”在水平方向创建一组“列(column)”。
- 你的内容应当放置于“列(column)”内,并且,只有“列(column)”可以作为行(row)”的直接子元素。
- 类似
.row
和.col-xs-4
这种预定义的类,可以用来快速创建栅格布局。Bootstrap 源码中定义的 mixin 也可以用来创建语义化的布局。 - 通过为“列(column)”设置
padding
属性,从而创建列与列之间的间隔(gutter)。通过为.row
元素设置负值margin
从而抵消掉为.container
元素设置的padding
,也就间接为“行(row)”所包含的“列(column)”抵消掉了padding
。 - 负值的 margin 就是下面的示例为什么是向外突出的原因。在栅格列中的内容排成一行。
- 栅格系统中的列是通过指定 1 到 12 的值来表示其跨越的范围。例如,三个等宽的列可以使用三个
.col-xs-4
来创建。 - 如果一“行(row)”中包含了的“列(column)”大于 12,多余的“列(column)”所在的元素将被作为一个整体另起一行排列。
- 栅格类适用于与屏幕宽度大于或等于分界点大小的设备 , 并且针对小屏幕设备覆盖栅格类。 因此,在元素上应用任何
.col-md-*
栅格类适用于与屏幕宽度大于或等于分界点大小的设备 , 并且针对小屏幕设备覆盖栅格类。 因此,在元素上应用任何.col-lg-*
不存在, 也影响大屏幕设备。
栅格原理是本质是设置百分比,即流式布局
offset:通过 margin,因此会影响其他元素导致换行
列排序
push:通过定位,可能会重叠
pull:通过定位,可能会出现
hidden-xs:在某一屏幕隐藏
less
LESS 是动态的样式表语言,通过简洁明了的语法定义,使编写 CSS 的工作变得非常简单,本质上,LESS 包含一套自定义的语法及一个解析器。
安装
1、安装 Nodejs 环境 Node Package Manager (验证 node -v npm -v) npm:node packge manager
2、打开控制台(cmd),执行 npm install -g less (验证 lessc -v) node packet manager
3、命令行编译 lessc path/xxx.less path/xxx.css
编译
浏览器只能识别 CSS,LESS 只是用来提升 CSS 可维护性的一个工具,所最终需要将 LESS 编译成 CSS,然而通过命令行编译效率比较低下,一般都会借助于编辑器来完成编译,以 sublime_text 为例,sublime_text 默认并不支持 LESS 的编译操作,需要安装插件实现。
1、执行 npm install -g less-plugin-clean-css(使用 sublime_text 才用)
2、ctrl+shit+p 打开命令面板
3、输入 install package 然后回车
4、安装 LESS、lessc、Less2Css 三个插件
5、alt+s 快捷键即可实现编译
less 语法
1 | //语法修改 |
垂直水平居中
1.水平居中
脱离文档流
- margin:o auto;
- 负 margin 法:先 left:50%,然后在给一个负 margin-left 居中元素宽度的一半
- transform: translateX:-50%
- 给父容器设置 text-align :center, 然后给子容器加上 display:inline-block;
2.垂直居中
脱离文档流
- margin: auto 0;
- 负 margin 法:先 top:50%,然后在给一个负 margin-top 居中元素宽度的一半
- transform: translateY:-50%
3.table-cell 法 和 flex 弹性盒子法
table-cell 法(对低版本 IE 兼容比较良好)
1 | div { |
flex 法:
1 | .container { |
三角形画法
从底向上
1 | #triangle-up { |
transparent 属性相当于 rgba(0,0,0,0,)全透明的颜色
清除浮动的方法
BFC 消除浮动法:给父盒子加上 overflow:hidden;
优点: 代码简洁
缺点: 内容增多时候容易造成不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素。
- 额外标签法:在浮动元素末尾添加一个空的标签例如 ,或则其他标签 br 等亦可。
优点: 通俗易懂,书写方便
缺点: 添加许多无意义的标签,结构化较差。
使用 after 伪元素清除浮动(推荐)
```css
.clearfix:after {content: '.'; display: block; height: 0; clear: both; visibility: hidden;
}
.clearfix {
*zoom: 1;
} /* IE6、7 专有 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 优点: 符合闭合浮动思想 **结构语义化正确**
缺点: 由于 IE6-7 不支持:after,使用 zoom:1 触发 hasLayout。
### background 属性详解
- background-color 背景颜色
- **background-position 背景图片位置(精灵图常用)**
- background-size :规定背景图像的尺寸
- **background-repeat:属性设置是否及如何重复背景图像。(精灵图常用)**
- background-origin:相对于内容框来定位背景图像(目前不常用)
- background-clip:规定背景的绘制区域(目前我不常用)background-clip: border-box|padding-box|content-box;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- **background-attachment:规定背景图像是否固定或者随着页面的其余部分滚动(可以用来视差滚动的效果)**
- **background-image:设置背景图片(精灵图常用)**
- 缩写方式(更简洁明了,且对低版本的兼容性更高)
```css
div {
// 缩写必须按顺序来
//(<颜色> <background-image背景图片> <background-repeat重复背景图片>
<background-attachment 背景固定方式> <背景图片位置>)
background: #ff0000 url(/i/eg_bg_03.gif) no-repeat fixed center;
}
兼容性问题
靠积累了这个,常见的要知道,比如 CSS3 新添加的动画和 transition,IE6.7.8 都不支持,以及一些 H5 标签的兼容性问题,JS 的原生方法如 getElementByClassName,IE 低版本不支持,可以采用兼容性写法等等,这个要靠平时多积累
1 | //1 getElementsByClassName方法在IE8以下版本不支持,因此采用这种写法 |
浏览器前缀
浏览器前缀 | 浏览器 |
---|---|
-webkit- | Google Chrome, Safari, Android Browser |
-moz- | Firefox |
-o- | Opera |
-ms- | Internet Explorer, Edge |
-khtml- | Konqueror |
H5 相关
块级元素和行内元素的区别
块级
1.块级元素独占一行,当没有设置宽高时,它默认设置为 100%
2.块级元素允许设置宽高,width、height、margin、padding、border 都可控制
3.块级元素可以包行内元素、块级元素
(有些特殊的块级元素不能包含块级元素,只能包含行内元素:h1~h6、p、dt)
行内
1.行内元素不能独占一行,与其他行内元素排成一行
2.行内元素不能设置 width、height、margin、padding
3.行内元素默认宽度为其 content 宽度
4.行内元素只能包括文字或行内元素、行内块元素,不能包括块级元素
5.display:inline-block:行内块元素与行内元素属性基本相同即不能独占一行,但是可以设置 width 及 height
(2)有一些特别的行内元素可以设置宽高
替换元素:、、
fetch API
标签语义化
H5 新加入的 API
localStorage、sessionStorage、Cookie
- localStorage - 没有时间限制的数据存储
- sessionStorage - 针对一个 session 的数据存储
canvas
SVG
web worker 是运行在后台的 JavaScript,不会影响页面的性能。(了解)
<参考:http://www.w3school.com.cn/html5/html_5_webworkers.asp>
地理定位
常用布局
圣杯布局
优先渲染中间栏适应
两边侧边栏固定,中间自适应
1 |
|
双飞翼布局
1 |
|
BFC
BFC(Block formatting context)块级格式化上下文
display 属性为 block, list-item, table 的元素,能产生 BFC.
同样,要给这些元素添加如下属性就可以触发 BFC。
-float 属性不为 none
-position 为 absolute 或 fixed
-display 为 inline-block, table-cell, table-caption, flex, inline-flex
-overflow 不为 visible。
BFC 元素所具有的特性
BFC 布局规则特性:
1.在 BFC 中,盒子从顶端开始垂直地一个接一个地排列.
2.盒子垂直方向的距离由 margin 决定。属于同一个 BFC 的两个相邻盒子的 margin 会发生重叠
3.在 BFC 中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来说,则触碰到右边缘)。
- BFC 的区域不会与浮动盒子产生交集,而是紧贴浮动边缘。
- 计算 BFC 的高度时,自然也会检测浮动或者定位的盒子高度。
它是一个独立的渲染区域,只有 Block-level box 参与, 它规定了内部的 Block-level Box 如何布局,并且与这个区域外部毫不相干。
BFC 的主要用途
(1) 清除元素内部浮动
只要把父元素设为 BFC 就可以清理子元素的浮动了,最常见的用法就是在父元素上设置 overflow: hidden 样式,对于 IE6 加上 zoom:1 就可以了。
主要用到
1 | 计算BFC的高度时,自然也会检测浮动或者定位的盒子高度。 |
(2) 解决外边距合并问题
外边距合并的问题。
主要用到
1 | 盒子垂直方向的距离由margin决定。属于同一个BFC的两个相邻盒子的margin会发生重叠 |
属于同一个 BFC 的两个相邻盒子的 margin 会发生重叠,那么我们创建不属于同一个 BFC,就不会发生 margin 重叠了。
(3) 制作右侧自适应的盒子问题
主要用到
1 | 普通流体元素BFC后,为了和浮动元素不产生任何交集,顺着浮动边缘形成自己的封闭上下文 |
BFC 总结
BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。包括浮动,和外边距合并等等,因此,有了这个特性,我们布局的时候就不会出现意外情况了。
渐进增强和优雅降级
渐进增强
progressive enhancement:
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级
graceful degradation:
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
背景渐变
在线性渐变过程中,颜色沿着一条直线过渡:从左侧到右侧、从右侧到左侧、从顶部到底部、从底部到顶部或着沿任何任意轴。
兼容性问题很严重,必须加上浏览器前缀。
线性渐变语法格式:
1 | background: -webkit-linear-gradient(渐变的起始位置, 起始颜色, 结束颜色) ;; |
1 | background: -webkit-linear-gradient(渐变的起始位置, 颜色 位置, 颜色位置....) ;; |
echarts 图表
layer ui 框架
JS
原生 JS
1.最基本的:隐式转换、数组、字符串、正则 、Date 相关方法及 DOM 操作
dom 操作:增删改查,操作节点
bom:bom 对象,事件,表单
错误处理
2.函数:作用域、闭包、垃圾回收
this 相关:this 指向问题
手写 bind()、call()、apply()
3.对象 :原型、原型链、构造函数、创建对象的模式、继承、包装对象、深拷贝、浅拷贝、深复制、浅复制
4.同步异步:async 与 await、定时器、微任务,宏任务
4.ES6 相关:let 和 const、模板字符串、promise、类、super、static 以及
5.ES6 新加方法:Object.assign()
6.额外技能:github issue 、资料查阅工具等等
7.工作常用: 数组列表 分页
深拷贝
这个文章写得非常好https://www.jianshu.com/p/b08bc61714c7
日常开发常用深拷贝,序列化反序列化法
唯一局限性:只能深拷贝对象和数组,对于其他种类的对象,会失真。
1 | function deepClone(obj) { |
搞事情深拷贝:能拷贝自身可枚举、自身不可枚举、自身 Symbol 类型键、原型上可枚举、原型上不可枚举、原型上的 Symol 类型键,循环引用也可以拷的深拷贝函数:2333.
1 | // 将之前写的 deepClone 函数封装一下 |
作用域
编程语言有两种:词法作用域和动态作用域
JavaScript 为词法作用域
相关:引擎、编译器、作用域
词法作用域,LHS 和 RHS 引用
函数作用域和块作用域
闭包
实质:当函数可以记住并访问 所在的词法作用域, 即使函数是在当前词法作用域之外执行的,这时候就会产生闭包
能够访问其他函数内部局部变量的函数
能将局部变量的值保存在内存中
在数组中保存函数
一个函数引用外部局部变量也是闭包
可以做一个预编译的函数
模块化:
两个特征:1.为创建内部作用域调用了一个包装函数 2.包装函数的返回值至少包括一个对内部函数的引用,这样就会创建涵盖着呢哥哥包装函数内部作用域的闭包
import
可以将一个模块中的一个或者多个 API 导入到当前作用域中,并分别绑定在一个变量上
module
会将整个模块的 API 导入并绑定到一个变量上
export
会将当前模块的一个标识符(变量,函数)导出为公共 API
这些操作可以在模块定义中根据需要使用任意多次
内存泄漏
指随着时间的推移,某些不再需要的变量一直没有被释放,意味着浏览器的可用内存会逐渐的减少,直至没有多余内存泄漏,浏览器进程被迫崩溃。
三种情况发生内存泄漏
1.使用 console 对象在浏览器开发者工具的 JavaScript 控制台里输出对象的值,会引发内存泄漏,发布代码时将这些消息输出方法调用移除,提防这一点
2.对 JavaScript 函数闭包的引用是网页应用程序内存泄漏的另一个常见来源,故对于事件处理器闭包,要确保在 dom 元素上使用 removeEventListener()方法,以保证将不再需要使用的对象引用及时移除
3.两个或更多的对象之间的循环引用,应用程序已经不再需要这些对象,但是对象仍然保持着分配的内存,因此,将来自于其他对象的数据引用以独立的局部变量形式保存为一个副本
this 相关
this 的绑定机制类似于动态作用域,在哪里调用则绑定哪里
有四条绑定规则:默认绑定、隐式绑定、显式绑定、new 绑定
判断 this 绑定方法:
1.找到运行中函数的直接调用位置
2.判断规则:(即优先级)
由 new 调用?绑定到新创建的对象
由 call,bind,apply 调用?绑定到指定的对象
由上下文对象调用?绑定到调用的上下文对象
都没有,则看有无严格模式,严格模式下为 undefined,否则为全局对象
3.例外情况:箭头函数中的 this:根据当前词法作用域决定,即箭头函数会继承外层函数调用的 this 绑定,无论 this 绑定的是什么
数组去重
第一种方法:indexOf():查找当前查询值在当前数组的索引,如果不存在则返回-1
建立新数组,拿到旧数组的每一位,如果新数组不存在,那么就 push 进去
1 | function unique1(arr) { |
第二种方法:
将数组的元素值作为对象的属性名,借助对象 obj{}:同个对象中不能有同样的属性名
1 | function unique2(arr) { |
第三种方法:ES6 的 symbol
1 | new Set(arr) |
DOM
原生 JS 添加类名 删除类名
1 | 为 <div> 元素添加 class: |
代码优化
避免双重解释:js 代码想解析 js 代码出现双重解释,非常浪费性能,会创建一个新的 js 解释器来解释内部的 js 代码
当使用 eval()函数或是 Function 构造函数以及 setTimeout()传一个字符串时都会发生这种情况。如下
1 | //eval// |
异步
常见的微任务有: process.nextTick、Promise 和 MutationObserver 监听 DOM 的变化。
常见的宏任务: setTimeout、setInterval、setImmediate、 script 中整体的代码、 I/O 操作、 UI 渲染等。
AJAX
同源策略
同源是指,域名,协议,端口相同。
浏览器这个策略的本质是一个域名的 JS ,在未经允许的情况下,不得读取另一个域名的内容。但浏览器并不阻止你向另一个域名发送请求,只是在接收加载资源之前对其来源进行了检查,然后限制加载。即拦截的是服务器响应回来的数据。
cors 跨域
http://www.cnblogs.com/moretry/p/4154479.html
在我们日常的项目开发时使用 AJAX,传统的 Ajax 请求只能获取在同一个域名下面的资源,但是 HTML5 打破了这个限制,允许 Ajax 发起跨域的请求。浏览器是可以发起跨域请求的,比如你可以外链一个外域的图片或者脚本。但是 Javascript 脚本是不能获取这些资源的内容的,它只能被浏览器执行或渲染。主要原因还是出于安全考虑,浏览器会限制脚本中发起的跨站请求。(同源策略, 即 JavaScript 或 Cookie 只能访问同域下的内容)。跨域的解决方案有多重 JSONP、Flash、Iframe 等,当然还有CORS(跨域资源共享,Cross-Origin Resource Sharing)今天就来了解下 CORS 的原理,以及如何使用。
一、CORS 概述
跨源资源共享标准通过新增一系列 HTTP 头,让服务器能声明那些来源可以通过浏览器访问该服务器上的各类资源(包括 CSS、图片、JavaScript 脚本以及其它类资源)。另外,对那些会对服务器数据造成破坏性影响的 HTTP 请求方法(特别是 GET 以外的 HTTP 方法,或者搭配某些 MIME 类型的 POST 请求),标准强烈要求浏览器必须先以 OPTIONS 请求方式发送一个预请求(preflight request),从而获知服务器端对跨源请求所支持 HTTP 方法。确认服务器允许该跨源请求的情况下,以实际的 HTTP 请求方法发送那个真正的请求。服务器端也可以通知客户端,是不是需要随同请求一起发送信用信息(包括 Cookies 和 HTTP 认证相关数据)。
二、CORS 原理
例如:域名 A(http://a.example)的某 Web 应用程序中通过标签引入了域名 B(http://b.foo)站点的某图片资源(http://b.foo/image.jpg)。这就是一个跨域请求,请求http报头包含Origin: http://a.example,如果返回的http报头包含响应头 Access-Control-Allow-Origin: http://a.example (或者 Access-Control-Allow-Origin: http://a.example),表示域名B接受域名B下的请求,那么这个图片就运行被加载。否则表示拒绝接受请求。
三、CORS 跨域请求控制方法
1.http 请求头
Origin: 普通的 HTTP 请求也会带有,在 CORS 中专门作为 Origin 信息供后端比对,表明来源域。
Access-Control-Request-Method: 接下来请求的方法,例如 PUT, DELETE 等等
Access-Control-Request-Headers: 自定义的头部,所有用 setRequestHeader 方法设置的头部都将会以逗号隔开的形式包含在这个头中
2.http 响应头
然后浏览器再根据服务器的返回值判断是否发送非简单请求。简单请求前面讲过是直接发送,只是多加一个 origin 字段表明跨域请求的来源。然后服务器处理完请求之后,会再返回结果中加上如下控制字段
Access-Control-Allow-Origin: 允许跨域访问的域,可以是一个域的列表,也可以是通配符”*“。这里要注意 Origin 规则只对域名有效,并不会对子目录有效。即http://foo.example/subdir/ 是无效的。但是不同子域名需要分开设置,这里的规则可以参照同源策略
Access-Control-Allow-Credentials: 是否允许请求带有验证信息,XMLHttpRequest 请求的 withCredentials 标志设置为 true 时,认证通过,浏览器才将数据给脚本程序。
Access-Control-Expose-Headers: 允许脚本访问的返回头,请求成功后,脚本可以在 XMLHttpRequest 中访问这些头的信息
Access-Control-Max-Age: 缓存此次请求的秒数。在这个时间范围内,所有同类型的请求都将不再发送预检请求而是直接使用此次返回的头作为判断依据,非常有用,大幅优化请求次数
Access-Control-Allow-Methods: 允许使用的请求方法,以逗号隔开
Access-Control-Allow-Headers: 允许自定义的头部,以逗号隔开,大小写不敏感
四、浏览器支持情况
在大部分现代浏览器中有所支持,支持(部分支持)CORS 协议的浏览器有 IE8+, Firefox5+, Chrome12+, Safari4+,移动端几乎全支持。
注:Internet Explorer 8 、9 使用 XDomainRequest 对象实现 CORS。
五、CORS 使用案例
案例环境:客户端使用 jQuery,服务端 WebApi(2.2)。因本人使用.net 语言,所以服务端就使用 webApi 来演示了。
首先新建一个 webApi 项目,这里就不截图一步步介绍了,然后使用 Nuget 安装支持 cors 的扩展组件,
Install-Package Microsoft.AspNet.WebApi.Cors
然后打开 App_Start 问价夹下的 WebConfig.cs 配置文件类,在 Register 方法中配置一个全局的 cors,为了方便我将一些参数配置到 web.config 配置文件中
1 | <add key="cors_allowOrigins" value="*"/> |
1 | var allowOrigins = ConfigurationManager.AppSettings["cors_allowOrigins"]; |
如果不想使用全局的 CORS,可以在某个方法或者 ApiController 上这样配置:[EnableCors(origins: ““, headers: ““, methods: “*”)],可以使用具体的参数,多个参数以逗号分隔,不用说,肯定英文逗号。origins 域名要带上 http 的顶级域名。需要添加 using System.Web.Http.Cors;
一般请求来说,客户端的 AJAX 请求不需要做任何改变,只需要服务端稍作改变即可。
客户端 js 代码: apiRootPath 是我预先设置的 api 的顶级域名。
1 | $.ajax({ |
因为我配置了全局的 CORS 方法,而且服务端没有特别之处了,和普通的网站(不跨越)写法一致,这里就不予贴出了。
如果需要对请求进行身份验证,怎么办?我们一 cookies 实现这个验证。
1 | $.ajax({ |
注意这个两句话:crossDomain: true,xhrFields: {withCredentials: true}
六:安全隐患
如果程序猿偷懒将 Access-Control-Allow-Origin 设置为:Access-Control-Allow-Origin: * 允许任何来自任意域的跨域请求,那么久存在被 DDoS 攻击的可能。
原型和构造函数
原型是 function 对象的一个属性,该属性是一个对象
原型是本身就存在的
- 原型对象中有默认有两个属性,一个是 constructor,该属性指向基于该原型的实例的构造函数,
- 另一个属性是隐式属性
__proto
__
绝大多数对象的原型最终都指向 Object,除了特殊创建的无原型对象,如下
```javascript
var obj = Object.create(null)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
**该方法创建出来的对象无原型,并且如果后期为其指定 `__proto`\_\_属性,不会拥有继承特性!!**
null 和 undefined 是没有原型的
tip:null 为空对象指针,真正的空对象,{ }也是空的对象,但是还有原型属性
#### prototype 的应用:
1.用于提取共有属性
当我们使用构造函数创建属性时,如果出现重复的属性应该用原型来创建,可以减少代码量和冗余,即重复多次使用的属性应该用原型指配,构造函数用来指配特定的对象
#### 原型的增删改查
只能直接对原型进行操作才能成功,否则相当于直接对实例进行添加或修改
**特殊情况:引用值属性**
对于存在于父链上的引用值,如果进行增加可以使父链上的引用值本身发生变化,因为从子链上进行引用值取用,相当于直接对引用值本身进行操作
## DOM 阻塞相关

**什么情况下会发生阻塞?**
**1.遇到 script 标签加载 js 的时候**
会加载 js 并且执行完毕才开始渲染
**2.遇到 alert 会阻塞**
**3.css 也会阻塞**
css 是由单独的下载线程异步下载的。
总结:
1.css 加载**不会阻塞**DOM 树的**解析**
2.css 加载**会阻塞**DOM 树(render 树)的**渲染**
3.css 加载**会阻塞**后面 js 语句的执行
js 是全阻塞,css 会阻塞 js 的执行
JS 会阻塞后续 DOM 的解析和其它资源(如 CSS,JS 或图片资源)的加载。
css 加载不会阻塞 DOM 树的解析,不会阻塞其它资源(如图片)的加载,CSS 加载会阻塞 DOM 树的渲染,也会阻塞 JS 文件的执行。
**为了避免让用户看到长时间的白屏时间,我们应该尽可能的提高 css 加载速度,比如可以使用以下几种方法:**
使用 CDN(因为 CDN 会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间)
对 css 进行压缩(可以用很多打包工具,比如 webpack,gulp 等,也可以通过开启 gzip 压缩)
合理的使用缓存(设置 cache-control,expires,以及 E-tag 都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号)
减少 http 请求数,将多个 css 文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)
## 事件相关
#### 事件委托
参考资料:<https://www.cnblogs.com/liugang-vip/p/5616484.html>(事件委托)
<https://www.cnblogs.com/MarcoHan/p/5804362.html>(事件绑定、及相关)
**为什么要用事件委托:**
一般来说,dom 需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的 dom 需要添加事件处理呢?比如我们有 100 个 li,每个 li 都有相同的 click 点击事件,可能我们会用 for 循环的方法,来遍历所有的 li,然后给它们添加事件,那这么做会存在什么影响呢?
在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与 dom 节点进行交互,访问 dom 的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少 DOM 操作的原因;如果要用事件委托,就会将所有的操作放到 js 程序里面,与 dom 的操作就只需要交互一次,这样就能大大的减少与 dom 的交互次数,提高性能;
每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了(内存不够用,是硬伤,哈哈),比如上面的 100 个 li,就要占用 100 个内存空间,如果是 1000 个,10000 个呢,那只能说呵呵了,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。
事件委托的原理:
事件委托是利用**事件的冒泡原理**来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的 a 加一个 click 点击事件,那么这个事件就会一层一层的往外执行,执行顺序 a>li>ul>div,有这样一个机制,那么我们给最外面的 div 加点击事件,那么里面的 ul,li,a 做点击事件的时候,都会冒泡到最外层的 div 上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。
事件委托怎么实现:window.onload = function(){
var oUl = document.getElementById(“ul1”);
oUl.onclick = function(){alert(123);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这里用父级 ul 做事件处理,当 li 被点击时,由于冒泡原理,事件就会冒泡到 ul 上,因为 ul 上有点击事件,所以事件就会触发,当然,这里当点击 ul 的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击 li 才会触发,不怕,我们有绝招:
Event 对象提供了一个属性叫 target,可以返回事件的目标节点,我们称为事件源,也就是说,target 就可以表示为当前的事件操作的 dom,但是不是真正操作 dom,当然,这个是有兼容性的,标准浏览器用`ev.target`,IE 浏览器用`event.srcElement`,**此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用 nodeName 来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较**(习惯问题):
```javascript
window.onload = function () {
var oUl = document.getElementById('ul1')
oUl.onclick = function (ev) {
var ev = ev || window.event
var target = ev.target || ev.srcElement //兼容性写法
if (target.nodeName.toLowerCase() == 'li') {
alert(123)
alert(target.innerHTML)
}
}
}
这样改下就只有点击 li 会触发事件了,且每次只执行一次 dom 操作,如果 li 数量很多的话,将大大减少 dom 的操作,优化的性能可想而知!
上面的例子是说 li 操作的是同样的效果,要是每个 li 被点击的效果都不一样,那么用事件委托还有用吗?
1 | <div id="box"> |
1 | window.onload = function () { |
上面实现的效果我就不多说了,很简单,4 个按钮,点击每一个做不同的操作,那么至少需要 4 次 dom 操作,如果用事件委托,能进行优化吗?
1 | window.onload = function () { |
用事件委托就可以只用一次 dom 操作就能完成所有的效果,比上面的性能肯定是要好一些的
现在讲的都是 document 加载完成的现有 dom 节点下的操作,那么如果是新增的节点,新增的节点会有事件吗?也就是说,一个新员工来了,他能收到快递吗?
看一下正常的添加节点的方法:
1 | <input type="button" name="" id="btn" value="添加" /> |
现在是移入 li,li 变红,移出 li,li 变白,这么一个效果,然后点击按钮,可以向 ul 中添加一个 li 子节点
1 | window.onload = function () { |
这是一般的做法,但是你会发现,新增的 li 是没有事件的,说明添加子节点的时候,事件没有一起添加进去,这不是我们想要的结果,那怎么做呢?一般的解决方案会是这样,将 for 循环用一个函数包起来,命名为 mHover,如下:
1 | window.onload = function () { |
虽然功能实现了,看着还挺好,但实际上无疑是又增加了一个 dom 操作,在优化性能方面是不可取的,那么有事件委托的方式,能做到优化吗?
1 | window.onload = function(){ |
看,上面是用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在 js 里面的执行,这样可以大大的减少 dom 操作,这才是事件委托的精髓所在。
————————————————–华丽的分割线————– —————————————————————————————————–
在这里先感谢一下@苍茫大地 NV 的提问,提的问题非常好!👏👏👏
他的问题是:
现在给一个场景 ul > li > div > p,div 占满 li,p 占 满 div,还是给 ul 绑定时间,需要判断点击的是不是 li(假设 li 里面的结构是不固定的),那么 e.target 就可能是 p,也有可能是 div,这种情况你会怎么处理呢?
那我们现在就再现一下他给的场景
1 | <ul id="test"> |
如上列表,有 4 个 li,里面的内容各不相同,点击 li,event 对象肯定是当前点击的对象,怎么指定到 li 上,下面我直接给解决方案:
1 | var oUl = document.getElementById('test'); |
核心代码是 while 循环部分,实际上就是一个递归调用,你也可以写成一个函数,用递归的方法来调用,同时用到冒泡的原理,从里往外冒泡,知道 currentTarget 为止,当当前的 target 是 li 的时候,就可以执行对应的事件了,然后终止循环,恩,没毛病!
这里看不到效果,大家可以复制过去运行一下!
——————————————————————–华丽的分割线—————————————————————-
总结:
那什么样的事件可以用事件委托,什么样的事件不可以用呢?
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。
值得注意的是,mouseover 和 mouseout 虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。
不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说 focus,blur 之类的,本身就没用冒泡的特性,自然就不能用事件委托了。
Node.js
RESTful API
单线程
Node 可以在不新增额外线程的情况下,依然可以对任务进行并发处理 —— Node.js 是单线程的。它通过事件循环(event loop)来实现并发操作,对此,我们应该要充分利用这一点 —— 尽可能的避免阻塞操作,取而代之,多使用非阻塞操作。
非阻塞 IO
V8 虚拟机
事件驱动
AMD,Common.js
首先,JavaScript 是一个强大的脚本(函数式+面向对象)语言,它有很多快速高效的解释器,然而,它并没有一个用于更广泛应用程序的标准库。
CommonJS 是个规范,这个规范中定义了许多 API,用于普通应用程序(主要指非浏览器的应用)使用的 API,从而填补了这个空白。它的终极目标是提供一个类似 Python,Ruby 和 Java 标准库。这样的话,开发者可以使用 CommonJS API 编写应用程序,然后这些应用可以运行在不同的 JavaScript 解释器和不同的主机环境中。
NodeJS 就是 CommonJS 这个规范的实现者。
CommonJS 其中就有一个 Modules 规范,这个 Modules 规范设计之初是为了 server 端设计的,它是一个同步的模式,这种模式并不适合浏览器端,所以 AMD 规范诞生了,它最大的特点就是可以异步的方式加载模块。
RequrieJS 其实就是 AMD 现在用的最广泛,最流行的实现,其中,Require.js 主要提供 define 和 require 两个方法来进行模块化编程,前者用来定义模块,后者用来调用模块。
node.js 是单进程语言,发生错误了该怎么解决?
参考资料https://www.oschina.net/question/433035_171960?sort=time
使用 uncaughtException
try catch
node 的 forever
使用 shell 启动脚本守护 node
其是由一个无限循环 while true; 来实现的,为了防止过于密集的错误阻塞进程,每次错误后间隔 1 秒重启服务1
2
3
4
5
6
7
8
9
10
11
12
13WEB_DIR='/var/www/ourjs'
WEB_APP='svr/ourjs.js'
#location of node you want to use
NODE_EXE=/root/local/bin/node
while true; do
{
$NODE_EXE $WEB_DIR/$WEB_APP config.magazine.js
echo "Stopped unexpected, restarting \r\n\r\n"
} 2>> $WEB_DIR/error.log
sleep 1
done错误日志记录也非常简单,直接将此进程控制台当中的错误输出到 error.log 文件即可: 2>> $WEB_DIR/error.log 这一行, 2 代表 Error。
VUE
vue 的异步更新队列
当 vue 检测到数据变化时,不会马上去渲染 dom,而是创建一个队列,将变化载入队列中,等待事件执行结束,即下次事件循环开始时,将队列里的事情取出执行。(其实也就是和 js 异步里的事件轮询(event loop)差不多,宏任务和微任务)。所以要获取 dom 时,要使用$nextTick()保证在 dom 渲染出来后再进行获取
vue 的双向绑定
http://www.cnblogs.com/libin-1/p/6893712.html
通过 Object.defineProperty 的 get 和 set 进行数据挟持
mvvm 双向绑定
数据变化 data 更新视图 view:set 方法
视图变化 view 更新数据 data:事件监听
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器 Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者 Watcher 看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器 Dep 来专门收集这些订阅者,然后在监听器 Observer 和订阅者 Watcher 之间进行统一管理的。接着,我们还需要有一个指令解析器 Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者 Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者 Watcher 接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下 3 个步骤,实现数据的双向绑定:
发布者-订阅者模式
1.实现一个监听器 Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者 Watcher,作为连接 Observer 和 Compile 的桥梁,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器 Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
4、mvvm 入口函数,整合以上三者
网络基础
1.OSI,TCP/IP,五层协议的体系结构,以及各层协议
答:
OSI 分层 (7 层):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP/IP 分层(4 层):网络接口层、 网际层、运输层、 应用层。
五层协议 (5 层):物理层、数据链路层、网络层、运输层、 应用层。
每一层的协议如下:
物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器)
数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
传输层:TCP、UDP、SPX
会话层:NFS、SQL、NETBIOS、RPC
表示层:JPEG、MPEG、ASII
应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS
每一层的作用如下:
物理层:通过媒介传输比特,确定机械及电气规范(比特 Bit)
数据链路层:将比特组装成帧和点到点的传递(帧 Frame)
网络层:负责数据包从源到宿的传递和网际互连(包 PackeT)
传输层:提供端到端的可靠报文传递和错误恢复(段 Segment)
会话层:建立、管理和终止会话(会话协议数据单元 SPDU)
表示层:对数据进行翻译、加密和压缩(表示协议数据单元 PPDU)
应用层:允许访问 OSI 环境的手段(应用协议数据单元 APDU)
OSI 是 Open System Interconnection 的缩写,意为开放式系统互联。国际标准化组织(ISO)制定了 OSI 模型,该模型定义了不同计算机互联的标准,是设计和描述计算机网络通信的基本框架。OSI 模型把网络通信的工作分为 7 层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
Transmission Control Protocol/Internet Protocol 的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是 Internet 最基本的协议、Internet 国际互联网络的基础,由网络层的 IP 协议和传输层的 TCP 协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了 4 层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。通俗而言:TCP 负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而 IP 是给因特网的每一台联网设备规定一个地址。
2.IP 地址的分类
答:
A 类地址:以 0 开头, 第一个字节范围:1127(1.0.0.0 - 127.255.255.255);191(128.0.0.0 - 191.255.255.255);
B 类地址:以 10 开头, 第一个字节范围:128
C 类地址:以 110 开头, 第一个字节范围:192223(192.0.0.0 - 223.255.255.255);239(224.0.0.0 - 239.255.255.255);(作为多播使用)
D 类地址:以 1110 开头,第一个字节范围:224
E 类地址:保留
通过这张图可以很容易记住划分的范围,主要通过最开始的几个二进制位是 0 还是 1,来进行区分。
其中 A、B、C 是基本类,D、E 类作为多播和保留使用。
以下是留用的内部私有地址:
A 类 10.0.0.0–10.255.255.255
B 类 172.16.0.0–172.31.255.255
C 类 192.168.0.0–192.168.255.255
IP 地址与子网掩码相与得到网络号:
ip : 192.168.2.110
&
Submask : 255.255.255.0
网络号 :192.168.2 .0
注:主机号,全为 0 的是网络号(例如:192.168.2.0),主机号全为 1 的为广播地址(192.168.2.255)
IP 地址
我们都已经知道,Internet 是由几千万台计算机互相连接而成的。而我们要确认网络上的每一台计算机,靠的就是能唯一标识该计算机的网络地址,这个地址就叫做 IP(Internet Protocol 的简写)地址,即用 Internet 协议语言表示的地址。
在 Internet 里,IP 地址是一个 32 位的二进制地址,为了便于记忆,将它们分为 4 组,每组 8 位,由小数点分开,用四个字节来表示,而且,用点分开的每个字节的数值范围是 0~255,如 202.116.0.1,这种书写方法叫做点数表示法。
3.ARP 是地址解析协议,简单语言解释一下工作原理。
答:1:首先,每个主机都会在自己的 ARP 缓冲区中建立一个 ARP 列表,以表示 IP 地址和 MAC 地址之间的对应关系。
2:当源主机要发送数据时,首先检查 ARP 列表中是否有对应 IP 地址的目的主机的 MAC 地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送 ARP 数据包,该数据包包括的内容有:源主机 IP 地址,源主机 MAC 地址,目的主机的 IP 地址。
3:当本网络的所有主机收到该 ARP 数据包时,首先检查数据包中的 IP 地址是否是自己的 IP 地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的 IP 和 MAC 地址写入到 ARP 列表中,如果已经存在,则覆盖,然后将自己的 MAC 地址写入 ARP 响应包中,告诉源主机自己是它想要找的 MAC 地址。
4:源主机收到 ARP 响应包后。将目的主机的 IP 和 MAC 地址写入 ARP 列表,并利用此信息发送数据。如果源主机一直没有收到 ARP 响应数据包,表示 ARP 查询失败。
广播发送 ARP 请求,单播发送 ARP 响应。
地址解析协议,即 ARP(Address Resolution Protocol),是根据 IP 地址获取物理地址的一个 TCP/IP 协议。主机发送信息时将包含目标 IP 地址的 ARP 请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该 IP 地址和物理地址存入本机 ARP 缓存中并保留一定时间,下次请求时直接查询 ARP 缓存以节约资源。地址解析协议是建立在网络中各个主机互相信任的基础上的,网络上的主机可以自主发送 ARP 应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机 ARP 缓存;由此攻击者就可以向某一主机发送伪 ARP 应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个 ARP 欺骗。ARP 命令可用于查询本机 ARP 缓存中 IP 地址和 MAC 地址的对应关系、添加或删除静态对应关系等。相关协议有 RARP、代理 ARP。NDP 用于在 IPv6 中代替地址解析协议。
MAC(Media Access Control 或者 Medium Access Control)地址,意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。在 OSI 模型中,第三层网络层负责 IP 地址,第二层数据链路层则负责 MAC 地址。因此一个主机会有一个 MAC 地址,而每个网络位置会有一个专属于它的 IP 地址。 MAC 地址是网卡决定的,是固定的。
4.各种协议的介绍
答:ICMP 协议: 因特网控制报文协议。它是 TCP/IP 协议族的一个子协议,用于在 IP 主机、路由器之间传递控制消息。
TFTP 协议: 是 TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。
HTTP 协议: 超文本传输协议,是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。
NAT 协议:网络地址转换属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法 IP 地址的转换技术,
DHCP 协议:动态主机配置协议,是一种让系统得以连接到网络上,并获取所需要的配置参数手段,使用 UDP 协议工作。具体用途:给内部网络或网络服务供应商自动分配 IP 地址,给用户或者内部网络管理员作为对所有计算机作中央管理的手段。
ICMP 是(Internet Control Message Protocol)Internet 控制报文协议。它是 TCP/IP 协议族的一个子协议,用于在 IP 主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是 TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为 69。
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。
NAT(Network Address Translation,网络地址转换)是 1994 年提出的。当在专用网内部的一些主机本来已经分配到了本地 IP 地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信(并不需要加密)时,可使用 NAT 方法。
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,使用 UDP 协议工作, 主要有两个用途:给内部网络或网络服务供应商自动分配 IP 地址,给用户或者内部网络管理员作为对所有计算机作中央管理的手段,在 RFC 2131 中有详细的描述。DHCP 有 3 个端口,其中 UDP67 和 UDP68 为正常的 DHCP 服务端口,分别作为 DHCP Server 和 DHCP Client 的服务端口;546 号端口用于 DHCPv6 Client,而不用于 DHCPv4,是为 DHCP failover 服务,这是需要特别开启的服务,DHCP failover 是用来做“双机热备”的。
5.描述 RARP 协议
答:RARP 是逆地址解析协议,作用是完成硬件地址到 IP 地址的映射,主要用于无盘工作站,因为给无盘工作站配置的 IP 地址不能保存。工作流程:在网络中配置一台 RARP 服务器,里面保存着 IP 地址和 MAC 地址的映射关系,当无盘工作站启动后,就封装一个 RARP 数据包,里面有其 MAC 地址,然后广播到网络上去,当服务器收到请求包后,就查找对应的 MAC 地址的 IP 地址装入响应报文中发回给请求者。因为需要广播请求报文,因此 RARP 只能用于具有广播能力的网络。
反向地址转换协议(RARP:Reverse Address Resolution Protocol) 反向地址转换协议(RARP)允许局域网的物理机器从网关服务器的 ARP 表或者缓存上请求其 IP 地址。网络管理员在局域网网关路由器里创建一个表以映射物理地址(MAC)和与其对应的 IP 地址。当设置一台新的机器时,其 RARP 客户机程序需要向路由器上的 RARP 服务器请求相应的 IP 地址。假设在路由表中已经设置了一个记录,RARP 服务器将会返回 IP 地址给机器,此机器就会存储起来以便日后使用。 RARP 可以使用于以太网、光纤分布式数据接口及令牌环 LAN
6.TCP 三次握手和四次挥手的全过程
答:
三次握手:
第一次握手:客户端发送 syn 包(syn=x)到服务器,并进入 SYN_SEND 状态,等待服务器确认;
第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=x+1),同时自己也发送一个 SYN 包(syn=y),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;
第三次握手:客户端收到服务器的 SYN + ACK 包,向服务器发送确认包 ACK(ack=y+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP 连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
四次挥手
与建立连接的“三次握手”类似,断开一个 TCP 连接则需要“四次握手”。
第一次挥手:主动关闭方发送一个 FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了(当然,在 fin 包之前发送出去的数据,如果没有收到对应的 ack 确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。
第二次挥手:被动关闭方收到 FIN 包后,发送一个 ACK 给对方,确认序号为收到序号+1(与 SYN 相同,一个 FIN 占用一个序号)。
第三次挥手:被动关闭方发送一个 FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
第四次挥手:主动关闭方收到 FIN 后,发送一个 ACK 给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
关于 TCP 的三次握手四次挥手
拓展资料:https://juejin.im/post/5ccd0dfc6fb9a0324a08bb73
SYN:握手建立信号
ACK:应答同意信号
FIN:挥手信号(断开连接信号)
seq:包的序列号用于分割发送时判断怎么合并
ack:确认号,发送包的序列号
tip:SYN 攻击
SYN 攻击就是在客户端发送 SYN 信号给服务器端建立连接,但是还未收到服务器端的答复时,被黑客伪造请求发送随机 IP的 SYN 请求给服务器,造成服务器的请求队列爆满,使正常的 SYN 信号无法送达,从而使服务器崩溃瘫痪的攻击。
当出现大量的半连接状态时,且源 IP 地址是随机的,基本可以判断收到了 SYN 攻击
解决办法:一类是通过防火墙、路由器等过滤网关防护,另一类是通过加固 TCP/IP 协议栈防范.但必须清楚的是,SYN 攻击不能完全被阻止,我们所做的是尽可能的减轻 SYN 攻击的危害,除非将 TCP 协议重新设计。
常见 http 请求头状态码
1XX:消息
2XX:成功
3XX:重定向
4XX:请求错误
5XX、6XX:服务器错误
常见状态代码、状态描述的说明如下。
200 OK:客户端请求成功。
400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized:请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用。
403 Forbidden:服务器收到请求,但是拒绝提供服务。
404 Not Found:请求资源不存在,举个例子:输入了错误的 URL。
500 Internal Server Error:服务器发生不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,举个例子:HTTP/1.1 200 OK(CRLF)。
HTTP2.0
了解:https://juejin.im/post/5a4dfb2ef265da43305ee2d0
7.在浏览器中输入www.baidu.com后执行的全部过程
答:1、客户端浏览器通过 DNS 解析到www.baidu.com 的 IP 地址 220.181.27.48,通过这个 IP 地址找到客户端到服务器的路径。客户端浏览器发起一个 HTTP 会话到 220.181.27.48,然后通过 TCP 进行封装数据包,输入到网络层。
2、在客户端的传输层,把 HTTP 会话请求分成报文段,添加源和目的端口,如服务器使用 80 端口监听客户端的请求,客户端由系统随机选择一个端口如 5000,与服务器进行交换,服务器把相应的请求返回给客户端的 5000 端口。然后使用 IP 层的 IP 地址查找目的端。
3、客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。
4、客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定 IP 地址的 MAC 地址,然后发送 ARP 请求查找目的地址,如果得到回应后就可以使用 ARP 的请求应答交换的 IP 数据包现在就可以传输了,然后发送 IP 数据包到达服务器的地址。
8.TCP 和 UDP 的区别?
答:TCP 提供面向连接的、可靠的数据流传输,而 UDP 提供的是非面向连接的、不可靠的数据流传输。
TCP 传输单位称为 TCP 报文段,UDP 传输单位称为用户数据报。
TCP 注重数据安全性,UDP 数据传输快,因为不需要连接等待,少了许多操作,但是其安全性却一般。
TCP 对应的协议和 UDP 对应的协议
TCP 对应的协议:
(1) FTP:定义了文件传输协议,使用 21 端口。
(2) Telnet:一种用于远程登陆的端口,使用 23 端口,用户可以以自己的身份远程连接到计算机上,可提供基于 DOS 模式下的通信服务。
(3) SMTP:邮件传送协议,用于发送邮件。服务器开放的是 25 号端口。
(4) POP3:它是和 SMTP 对应,POP3 用于接收邮件。POP3 协议所用的是 110 端口。
(5)HTTP:是从 Web 服务器传输超文本到本地浏览器的传送协议。
UDP 对应的协议:
(1) DNS:用于域名解析服务,将域名地址转换为 IP 地址。DNS 用的是 53 号端口。
(2) SNMP:简单网络管理协议,使用 161 号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。
(3) TFTP(Trival File Transfer Protocal),简单文件传输协议,该协议在熟知端口 69 上使用 UDP 服务。
9.DNS 域名系统,简单描述其工作原理。
答:当 DNS 客户机需要在程序中使用名称时,它会查询 DNS 服务器来解析该名称。客户机发送的每条查询信息包括三条信息:包括:指定的 DNS 域名,指定的查询类型,DNS 域名的指定类别。基于 UDP 服务,端口 53. 该应用一般不直接为用户使用,而是为其他应用服务,如 HTTP,SMTP 等在其中需要完成主机名到 IP 地址的转换。
DNS(Domain Name System,域名系统),万维网上作为域名和 IP 地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的 IP 数串。通过域名,最终得到该域名对应的 IP 地址的过程叫做域名解析(或主机名解析)。DNS 协议运行在 UDP 协议之上,使用端口号 53。在 RFC 文档中 RFC 2181 对 DNS 有规范说明,RFC 2136 对 DNS 的动态更新进行说明,RFC 2308 对 DNS 查询的反向缓存进行说明。
10.TCP 的三次握手过程?为什么会采用三次握手,若采用二次握手可以吗?
答:建立连接的过程是利用客户服务器模式,假设主机 A 为客户端,主机 B 为服务器端。
(1)TCP 的三次握手过程:主机 A 向 B 发送连接请求;主机 B 对收到的主机 A 的报文段进行确认;主机 A 再次对主机 B 的确认进行确认。
(2)采用三次握手是为了防止失效的连接请求报文段突然又传送到主机 B,因而产生错误。失效的连接请求报文段是指:主机 A 发出的连接请求没有收到主机 B 的确认,于是经过一段时间后,主机 A 又重新向主机 B 发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机 A 第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机 B,主机 B 以为是主机 A 又发起的新连接,于是主机 B 同意连接,并向主机 A 发回确认,但是此时主机 A 根本不会理会,主机 B 就一直在等待主机 A 发送数据,导致主机 B 的资源浪费。
(3)采用两次握手不行,原因就是上面说的失效的连接请求的特殊情况。
11.了解交换机、路由器、网关的概念,并知道各自的用途
答:1)交换机
在计算机网络系统中,交换机是针对共享工作模式的弱点而推出的。交换机拥有一条高带宽的背部总线和内部交换矩阵。交换机的所有的端口都挂接在这条背 部总线上,当控制电路收到数据包以后,处理端口会查找内存中的地址对照表以确定目的 MAC(网卡的硬件地址)的 NIC(网卡)挂接在哪个端口上,通过内部 交换矩阵迅速将数据包传送到目的端口。目的 MAC 若不存在,交换机才广播到所有的端口,接收端口回应后交换机会“学习”新的地址,并把它添加入内部地址表 中。
交换机工作于 OSI 参考模型的第二层,即数据链路层。交换机内部的 CPU 会在每个端口成功连接时,通过 ARP 协议学习它的 MAC 地址,保存成一张 ARP 表。在今后的通讯中,发往该 MAC 地址的数据包将仅送往其对应的端口,而不是所有的端口。因此,交换机可用于划分数据链路层广播,即冲突域;但它不 能划分网络层广播,即广播域。
交换机被广泛应用于二层网络交换,俗称“二层交换机”。
交换机的种类有:二层交换机、三层交换机、四层交换机、七层交换机分别工作在 OSI 七层模型中的第二层、第三层、第四层盒第七层,并因此而得名。
2)路由器
路由器(Router)是一种计算机网络设备,提供了路由与转送两种重要机制,可以决定数据包从来源端到目的端所经过 的路由路径(host 到 host 之间的传输路径),这个过程称为路由;将路由器输入端的数据包移送至适当的路由器输出端(在路由器内部进行),这称为转 送。路由工作在 OSI 模型的第三层——即网络层,例如网际协议。
路由器的一个作用是连通不同的网络,另一个作用是选择信息传送的线路。 路由器与交换器的差别,路由器是属于 OSI 第三层的产品,交换器是 OSI 第二层的产品(这里特指二层交换机)。
3)网关
网关(Gateway),网关顾名思义就是连接两个网络的设备,区别于路由器(由于历史的原因,许多有关 TCP/IP 的文献曾经把网络层使用的路由器(Router)称为网关,在今天很多局域网采用都是路由来接入网络,因此现在通常指的网关就是路由器的 IP),经常在家 庭中或者小型企业网络中使用,用于连接局域网和 Internet。 网关也经常指把一种协议转成另一种协议的设备,比如语音网关。
在传统 TCP/IP 术语中,网络设备只分成两种,一种为网关(gateway),另一种为主机(host)。网关能在网络间转递数据包,但主机不能 转送数据包。在主机(又称终端系统,end system)中,数据包需经过 TCP/IP 四层协议处理,但是在网关(又称中介系 统,intermediate system)只需要到达网际层(Internet layer),决定路径之后就可以转送。在当时,网关 (gateway)与路由器(router)还没有区别。
在现代网络术语中,网关(gateway)与路由器(router)的定义不同。网关(gateway)能在不同协议间移动数据,而路由器(router)是在不同网络间移动数据,相当于传统所说的 IP 网关(IP gateway)。
网关是连接两个网络的设备,对于语音网关来说,他可以连接 PSTN 网络和以太网,这就相当于 VOIP,把不同电话中的模拟信号通过网关而转换成数字信号,而且加入协议再去传输。在到了接收端的时候再通过网关还原成模拟的电话信号,最后才能在电话机上听到。
对于以太网中的网关只能转发三层以上数据包,这一点和路由是一样的。而不同的是网关中并没有路由表,他只能按照预先设定的不同网段来进行转发。网关最重要的一点就是端口映射,子网内用户在外网看来只是外网的 IP 地址对应着不同的端口,这样看来就会保护子网内的用户。
计算机基础
线程和进程
https://www.cnblogs.com/fuchongjundream/p/3829508.html
1、进程
狭义定义:进程就是一段程序的执行过程。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
简单的来讲进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
进程状态:进程有三个状态,就绪、运行和阻塞。就绪状态其实就是获取了出 cpu 外的所有资源,只要处理器分配资源就可以马上执行。就绪状态有排队序列什么的,排队原则不再赘述。运行态就是获得了处理器分配的资源,程序开始执行。阻塞态,当程序条件不够时候,需要等待条件满足时候才能执行,如等待 i/o 操作时候,此刻的状态就叫阻塞态。
2、程序
说起进程,就不得不说下程序。先看定义:程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程则是在处理机上的一次执行过程,它是一个动态的概念。这个不难理解,其实进程是包含程序的,进程的执行离不开程序,进程中的文本区域就是代码区,也就是程序。
3、线程
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
4、多线程
在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。
1、进程与线程的区别:
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
三、说说优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在 SMP(多核处理机)机器上运行,而进程则可以跨机器迁移。
缓存相关(非常重要)
cache 替换策略
FIFO 算法 :先进先出算法
(好!)LRU 算法 :最近最久未使用算法
软件生存周期
1.可行性分析与项目开发计划
要解决的问题是什么?该问题有可行的解决办法吗?
对问题定义,分析,制定开发计划
产生:可行性分析报告、项目开发计划
2.需求分析
准确定义 软件系统必须做什么,确定软件系统的功能,性能,数据,界面要求,确定系统的逻辑模型
产生:软件需求说明书
3.概要设计
将确定的功能转换成需要的体系结构,分成明确模块,模块与需求功能对应,确定数据结构,确定数据类型
产生:概要设计说明书
4.详细设计
对模块功能进行具体描述,将功能描述转成精确的、结构化的过程描述,即对模块功能具体进行实现
产生 :详细设计文档
5.编码
6.测试
单元测试、集成测试、系统测试、验收测试
产生:软件测试计划、测试用例、软件测试报告
7.维护
最长的阶段,扩充,修复,适应性调整,增强
JavaScript 设计模式
常用
设计原则
单例模式
代理模式
建造者模式
概念解读:
使用设计模式是为了让系统代码可重用、可拓展、可解耦,使设计模式工程化
设计原则:
设计原则是设计模式依赖原则
- 开闭原则:对拓展开发,对修改关闭,如高考的试卷
- 里氏转换原则:子类继承父类,单独调用完全可以允许,比如盗版光盘
- 依赖倒转原则:引用一个对象,如果这个对象有底层类型,直接引用底层
- 接口隔离原则:每一个接口都应该是单独一种角色,只有单独一种功能
- 合成/聚合复用原则:新的对象应使用一些已有的对象,使之成为新对象的一部分
- 迪米特原则:一个对象应对其他对象尽可能少的了解
单例模式
概念
单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,确保一个类只有一个实例对象。
单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象
作用
1.模块间通信
2.系统中 某个类的对象只能存在一个
3.保护自己的属性和方法
使用的注意事项
1.注意 this 的使用
2.闭包容易造成内存泄漏,不需要的赶快回收
3.注意 new 的成本
代码示例
1 | /*1.独立的对象 建立两个a和b |