gdccwxx 的布洛阁


  • 首页

  • 关于

  • 标签

  • 归档

  • 搜索

计算机网络--物理层

发表于 2018-01-17
  • 物理层概念
    机械特性:指明接口所用接线器的形状和尺寸、引线数目和排列、固定和锁定装置等等。
    电气特性:指明在接口电缆的各条线上出现的电压的范围。
    功能特性:指明某条线上出现的某一电平的电压表示何种意义。
    过程特性:指明对于不同功能的各种可能事件的出现顺序。

  • 物理层作用
    计算机网络设备之间的连接必须依靠物理层的传输介质和相关协议进行。物理层主要负责在物理传输介质之上为“数据链路层”提供一个原始比特流(也就是数据是以一个个0或1的二进制代码形式表示的)的物理连接。其具体作用如下:

  • 构建数据通路
    “数据通路”就是完整的数据传输通道,可以是一段物理介质,也可以是由多段物理介质连接而成的。一次完整的数据传输,包括激活物理连接、传送数据、终止物理连接三个主要阶段。所谓“激活物理连接”,就是不管有多少段物理介质参与,在通信的两个数据终端设备间都要在电气上连接起来,形成一条可以在上面连续传输数据的通路。

  • 透明传输
    物理层中可用的传输介质类型(如不同类型的同轴电缆、双绞线和光纤等)非常多,各自又有相应的通信协议和标准来支持,这就决定了不同的计算机网络可能有不同的“路”。物理层除了要把这些不同的“路”修好外,还要确保这些不同的“路”能“连通”起来,形成通路,最终实现把比特流传输到对端“物理层”,然后向“数据链路层”提交的目的。

  • 要实现上述功能,需要物理层具有屏蔽不同传输介质类型和通信协议的功能,让进行网络通信的各方只看到有“路”可行,而不管修这些“路”所用的具体“材料”和相关标准,这就是物理层的“透明传输”功能。

  • 传输数据
    无论是从网络体系结构中哪层发起的通信,最终的数据都得通过最低的“物理层”传输出去,因为这是网络通信的唯一物理通道。但“物理层”的传输单位是比特(bit,也就是“位”,数据中的一个二进制的0或1就代表1位)。“物理层”的基本作用是在发送端通过物理层接口和传输介质将数据按比特流的顺序传送到接收端的物理层。

  • 数据编码
    要使数据能在“物理层”上有效、可靠地传输,最关键的是要确保数据比特流能在对应的“信道”中正常通过。这就涉及“物理层”的数据编码功能,因为不同传输介质所支持的数据编码类型不一样(如归零码、非归零码、曼彻斯特码、差分曼彻斯特码等)。

  • 信道的极限容量
    任何信道中,码元的传输的速率是有上限的,传输的速率超过上限,就会出现严重的码建传绕问题,是的接受段对码元的判决成为不可能。因此有了香浓公式C = Wlog2(1+S/N);

  • 数据传输管理
    “物理层”还具有一定的数据传输管理功能,如基于比特流的数据传输流量控制、差错控制、物理线路的激活和释放等。
    computer_internet

    信道复用

    频分复用(FDM)

    载波带宽(请注意,这里的“带宽”是频率带宽而不是数据的发送速率,每个子信道可以并行传送一路信号。FDM 用于模拟传输过程。
    e.g.——-广电HFC网络电视信号(FDM)

    1
    2
    3
    OFDM 正交频分复用
    OFDM系统比FDM系统要求的带宽要小得多,效率更高
    e.g.——-非对称的数字用户环线(ADSL)、数字视频广播(DVB)、高清晰度电视(HDTV)、无线局域网(WLAN)和第4代(4G)移动通信系统

时分复用(TDM)

在交互时间间隔内在同一信道上传送多路信号。TDM 广泛用于数字传输过程。
可能造成线路浪费,TDM信号又称的等时信号。
e.g.——–SDH(同步数字体系),ATM(异步传输模式),IP和HFC网络中CM(电缆调制解调器)与CMTS(电缆调制解调器终端系统)的通信

波分复用(WDM)

光的频分复用。在一根光纤上使用不同波长同时传送多路光波信号。WDM 用于光纤信道。WDM与FDM 基于相同原理但它应用于光纤信道的光波传输过程。

码分复用(CDM)

每个信道作为编码信道实现位传输(特定脉冲序列)。这种编码传输方式通过传输唯一的时间系列短脉冲完成,但在较长的位时间中则采用时间片断替代。每个信道,都有各自的代码,并可以在同一光纤上进行传输以及异步解除复用。

2017总结

发表于 2017-12-31

2017年,应该是我过的最艰苦的一年了。
2017年,也是学东西学的最多的一年。
2017年,也是身材变化最大的一年了。

病痛时间线
回顾2017年一整年。

2月底在家里穿鞋不小心扭伤腰
3月底在学校健身做俄罗斯转体拉伤筋膜
4月底实在忍受不了疼痛,回家修养了半个月
6月初发现自己精索静脉曲张
6月底去医院做了手术
7月份带病去工作室工作了一个月,去的那一天,还是一瘸以拐
11月底发现自己的腹股沟疼痛
12月底腰上,腹股沟疼痛难忍,最终去针灸治疗
想想还是很佩服我自己的20岁。在这个一整年中,几乎都是与病痛做斗争。看看自己的身体状况,精索静脉曲张是因为遗传行疾病,而腹股沟疼痛是因为筋缩,也就是因为寒冷,因为肝和肾没有和睾丸相通,所以导致疼痛。而腰上则是因为高考过多的劳累,休息不够,每天都因为学习,导致腰部腰肌劳损。
在回顾自己的这些个病痛史,发现自己还是很坚强。在面对病痛还是坚持学习,坚持带新生。虽然自己很倒霉,病痛是不经意间来到自己的身上,但是自己的表现还是可以给90分的。
加油!
学习时间线
回顾整个学习线
年初,看过一边编译与反编译。
大二下学期,在陈悦老师操作系统基础一课自认学的还不错。
大二下学期做一个微信小程序参加比赛,虽然没拿到奖,但是对小程序有了一定程度上的了解!
大二暑期获得一个环保主题的小奖。
大二暑假实训,一个月学了很多东西,重新拜读了一遍javascript高级教程,感觉学习颇多,再做了不少云家园的应用。对vue又重新有了新的认识。
大二暑期,对es6重新读了一遍,对js又有了新的认识。并且读了一边你不知道的js,收获颇多。
大三上,学校开课mfc和qt5,做了一个小应用,但是并不是很精细。
大三上,学校开课mssqlserver,对数据库的一些操作又有了新的认识。并且觉得操作系统和sqlserver中比如锁有这亲密的关系。
大三上,学校开课java,学习了java,并且用spring boot做了一个应用后端,感觉收获还是颇多。
大三上,学校开课计算机网络,对计算机网络和visual c++网络编程。
大三上,使用nodejs+mongodb开发了一个gpa热点,对mongodb和node的使用和构造有了一定的了解。
大三上,本来想用react 开发项目,只是写了demo就结束了
回顾整个2017年的学习路线,学习的不少,也自己安装了一个archlinux,对操作系统和linux操作系统有了新的认识。自己的一些技术栈的扩展,有了一定的提升,对于js这门语言,有了许多全新的认识,js与java结合,感觉有很多新的火花磨出来。记得6月28号手术那一天,为了赶一个比赛,第二天就开始躺在床上写代码,现在想起来不仅感慨。真心感觉当时很帅!为自己的毅力打99分。真的!这一年,我觉得自己最帅的一天,就是29号赶代码。自己还喝着稀饭,身子还不敢转动,自己还坚持写代码。这一年,自己真心经历了不少。
番外篇:
2017年还学习了一些其他的东西
开始学习了护肤。真心觉得可以遇见更好的自己。
和老爹一起完成了自己家的花园。
学习了蔡康永的说话之道一书,自己也规定每周三联系一位很久没有联系的朋友。
去上海和牡丹江旅游了一波,看到了不一样的地方,体验了不一样的开发者社区。
学了不少的穿搭,对颜色和穿搭有了一定的见解。
开始喝牛奶。
身材
回顾身材的改变
从过年的118到年后的122。假期的一些徒手健身,发现自己的公狗腰有了一定的变化。
到学校后健身,买了一个哑铃。身材保持在120。直到扭伤腰后一直停止健身到7月底。
手术后120,工作室第一个月,从120变成127,开始健身。127是健子肉。
暑期后是128,然后办了一张健身卡,体重到最近停止健身是132。
可能最近长了一些肉,体重到138左右,但是体脂率保持在18以下。
可以看到,从年前的118到现在的138,体重增长了20,身材也改变了不少。自手术后,吃好喝好。身材有了极大的变化。当然,我的目标是150到160。这一年不仅仅是肌肉的变化,其实可以很明显的发觉,健身的知识也增加了,并且改变了不少。学习了很多健身方面的知识。
总结:新的一年,学习了不少的东西,也做了很多东西。自己的改变是可以肉眼所见的。当然,也可能因为过于拼,所以身上有很多病症。当然,这一年的毅力也有了不小的提升。谢谢2017年的自己。虽然很累,但是很开心!
2018期望:希望2018年能学到更多,能进自己希望的大厂。学习到更多前沿的技术。父母亲人身体健康。自己爱的人和爱自己的人能够快快乐乐的生活!

你不知道的javascript————类型和语法

发表于 2017-12-17

类型

七个内置类型

  • 空值 (null)
  • 未定义 (undefined)
  • 布尔值 (boolean)
  • 数字 (number)
  • 字符串 (string)
  • 对象 (object)
  • 符号 (symbol)

检测各个类型

1
2
3
4
5
6
7
8
9
typeof undefined		=== "undefined" 	// true
typeof true === "boolean" // true
typeof 42 === "number" // true
typeof "42" === "string" // true
typeof {"life": 42} === "object" // true
typeof Symbol === "symbol" // true
typeof null === "object" // true
typeof function(){} === "function" // true
typeof [0,1] === "object" // true

本身null对象里面代表空值,所以其为object也是合理。但应该typeof null 返回是 null才符合常理。由于这个bug在许多代码中已经这样做了,所以重新修回会导致更严重的bug。因此被修回的可能性很小。
因此,对null应该采用复合查询语句

1
2
var a = null;
(!a && typeof a === "object") // true

而对于typeof function(){} === “function” 而言,因为本身function是object的一个子类型,具体的说,函数是一个可调用对象。
且typeof [0,1] === “object”,因为数组也是object的一个子类型

ps:由于所有的typeof都会返回一个string,所以 typeof typeof 42会是”string”,因为typeof 42首先会变成一个“number”,是一个string类型,所以typeof “number”是一个string

undefined && undeclared && typeof undeclared

1
2
3
4
5
6
7
8
9
var a;
typeof a; // "undefined"
var b = 42;
var c;
b=c;
typeof c // "undefined"
typeof b // "undefined"
a // "undefined"
d // "VM422:1 Uncaught ReferenceError: d is not defined at <anonymous>:1:1"

从上述可以看出,undefined 和 undeclared 是两码事。undefined意思是定义但未赋值,或者赋值为undefined,而undeclared是未定义。因此两者不能画等号

typeof undeclared

1
typeof a			// "undefined"

出现这种原因因为typeof有一个特殊的安全防范机制,因为多个脚本文件会在共享的全局变量命名空间中加载变量。如果typeof一个未命名的报错,会导致整段程序停止运行。对于typeof来检查undeclared变量,有时是一个不错的办法。

值

数组

js的数组可以容纳任何的值,甚至可以是另一个数组,因此多维数组就是这种方式来实现的。
由于数组本身就是一个特殊的对象,所以数组也可以包含字符串键值和属性,但是这并不计算在数组长度内。

1
2
3
4
5
6
7
8
var a = [];
a[0] = 1;
a["foobar"] = 1;
a.length // 1
a["foobar"]; // 1
a.foobar // 1
a["13"] = 42;
a.length // 14

为什么会这样呢?由于本身数组就是一个对象的子集合,因此在[]中,使用十进制字符串数字会直接强制类型转化成数字。a[“13”]就变成了a[13],因此在数组内会直接将其长度变化成14。同理,在属性给foobar加到a数组中,因为数组的界定是有数字来确定下标位置,而length是最后一个下标数字+1,因而加入的非数字就不在长度里面了。

类数组

对于es5而言,可以用slice,concat来实现类数组转数组,对于es6而言,可以用Array.from()来实现从类数组转换成数组。

字符串

字符串的一些方法indexOf(),concat(),toUpperCase(),reverse()等等。
字符串的一些方法:
|方法|描述|
|—|—|
|charAt() | 返回指定索引位置的字符|
|charCodeAt() | 返回指定索引位置字符的 Unicode 值|
|concat() | 连接两个或多个字符串,返回连接后的字符串|
|fromCharCode() | 将 Unicode 转换为字符串|
|indexOf() | 返回字符串中检索指定字符第一次出现的位置|
|lastIndexOf() | 返回字符串中检索指定字符最后一次出现的位置|
|localeCompare() | 用本地特定的顺序来比较两个字符串|
|match() | 找到一个或多个正则表达式的匹配|
|replace() | 替换与正则表达式匹配的子串|
|search() | 检索与正则表达式相匹配的值|
|slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分|
|split() | 把字符串分割为子字符串数组|
|substr() | 从起始索引号提取字符串中指定数目的字符|
|substring() | 提取字符串中两个指定的索引号之间的字符|
|toLocaleLowerCase() | 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射|
|toLocaleUpperCase() | 根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射|
|toLowerCase() | 把字符串转换为小写|
|toString() | 返回字符串对象值|
|toUpperCase() | 把字符串转换为大写|
|trim() | 移除字符串首尾空白|
|valueOf() | 返回某个字符串对象的原始值|

如果需要经常一字符数组的方式来处理字符串的话,倒不如直接用数组。这样就不用在字符串和数组之间来回折腾。可以在有需要的时候使用join(“”)来将字符串数组转换为字符串

数字

和大部分编程语言一样,js中的数字是基于IEE754标准来实现的。该标准通常也被称为“浮点数”。而js使用的是双精度单位(64位)格式。所以也会有iee754标准的通病,即浮点数之间相加会有奇妙的现象。
数字的一些方法:
toExponential()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = 5E10			// 可以通过这种方式赋值
a // 50000000000
a.toExponential() // "5e+10"
var b = a * a;
b // 2.5e+21
```
toFixed() // 精度
```bash
var a = 42.59
a.toFixed(1) // "42.6"
// 无效
42.toFixed(3) // Uncaught SyntaxError: Invalid or unexpected token
// 有效
42..toFixed(3) // "42.000"
(42).toFixed(3) // "42.000"
0.42.toFixed(3) // "0.420"
42 .toFixed(3) // "42.000"

因为.被视为常量42.的一部分。所以没有.属性访问运算符来调用toFixed()
toPrecision() // 执行有效位数的显示位数

1
2
3
4
5
6
7
8
9
10
var a = 42.59
a.toPrecision(1) // "4e+1"
a.toPrecision(2) // "43"
a.toPrecision(3) // "42.6"
```
es6支持新格式
```bash
0B 0b // 二进制
0O 0o // 八进制
0X 0x // 十六进制

EPSILON // 最小精度

1
2
3
if(((0.1 + 0.2) - 0.3)<Number.EPSILON){
}else{
}

MAX_VALUE
MAX_SAFE_INTEGER

1
2
Number.MAX_VALUE						// 1.7976931348623157e+308
Number.MAX_SAFE_INTEGER // 9007199254740991

isInteger

1
2
3
Number.isInteger(1)					// true
Number.isInteger(1.1) // false
Number.isInteger(1.0) // true

特殊数值

undefined
1
2
var undefined = 2
undefined // 2

ps:永远不要重新定义undefined

void 运算符

在不需要返回值的时候,可以void掉

1
2
3
if(ready){
return void setTimeout(..)
}

这样做可以将setTimeout返回的id给void掉

NaN

NaN是一个数值型。意思指的是不是一个数值,并且NaN != NaN。可以使用isNaN来判断是否是NaN

1
2
Number.isNaN(NaN)				// true
Number.isNaN(1) // false

0值

加法和减法运算永远不会有-0
使用toString和JSON.stringify()会将-0变成0

1
2
3
4
5
6
0/-1			// -0
0/1 // 0
var a = -0
a // -0
a.toString() // 0
JSON.stringify(a) // 0

特殊等式

Object.is
Object.is 可以判断是+0还是-0,而且可以判断是否为NaN

1
2
Object.is(+0, -0)	// false
Object.is(NaN, NaN) // true

值和引用

null,undefined,字符串,数字,布尔,symbol都是简单值
对象,函数都是复杂值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function foo(x) {
x.push(4);
x; // [1,2,3,4]
x = [4,5,6];
x.push(7);
x; // [4,5,6,7]
}
var a = [1,2,3];
foo(a);
a; // [1,2,3,4]
由于一开始是引用赋值,然后x是a对应数组的一个引用,x在push一个4之后,重新引用一个新的数组,4.5.6,而a引用的数组变化成了[1,2,3,4];
function foo(x){
x.push(4);
x; // [1,2,3,4]
x.length = 0;
x.push(4,5,6,7)
x; // [4,5,6,7]
}
var a = [1,2,3]
foo(a)
a; // [4,5,6,7]
和上面一开始一样,只是后面在x.length=0后,再push进去了4,5,6,7。所以x的引用没变,还是和a引用的一样。所以a和x一同变化

ps:我们无法自行决定使用值赋值还是引用赋值,一切由值的类型决定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function foo(warpper){
warpper.a = 42
}
var obj = {
a: 1
}
foo(obj)
obj.a //42
function foo (x) {
x = x+1;
x; // 3
}
var a = 2;
var b = new Number(a);
foo(b)
console.log(b) // 2
前者是引用赋值,后者是值赋值

原生函数

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Function
  • RegExp
  • Date
  • Error
  • Symbol

内部属性[[Class]]

所有typeof返回值为“Object”的对象(如数组)都包含一个内部属性[[Class]],这个属性通常无法直接访问,一般通过Object.prototype.toString查看

1
2
3
4
Object.prototype.toString.call([123])			// "[object Array]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(undefined) // "[object Undefined]"

虽然Null和undefined这样的原声构造函数不存在,但是内部Class属性值仍然是Null和Undefined。基本类型值被各自的封装对象自动包装,所以他们的内部[[Class]]属性值为Boolean。

封装对象包装

1
2
3
4
5
var a = "abc";
console.log(a); // "abc"
a.length // "3"
var b = new String("abc")
console.log(b) // String {[[PrimitiveValue]]: "abc"} 0:"a" 1:"b" 2:"c" length:3 __proto__:String [[PrimitiveValue]]:"abc"

只是创建字面量基本值的时候,并没有其他的方法。当在使用其对象方法时,需要通过封装对象才能访问,此时js会自动为基本类型值包装(box或者wrap)一个封装对象。
但是为经常用到的.length方法直接new一个对象也不是一个好办法,因为浏览器对.length这样的常见情况做了优化,直接使用封装对象来“提前优化”反而会降低执行效率。

封装对象的释疑

例如:

1
2
3
4
var a = new Boolean(false);
if (!a){
console.log(...) // 执行不到这里
}

因为建立一个a之后,这个对象得到的是真值,得到的结果和使用false相反

自行封装可以使用Object

1
2
3
4
5
6
7
8
9
10
var a = "abc"
var b = new String (a);
var c = Object(a);
typeof a // "stirng"
typeof b // "object"
typeof c // "object"
b instanceof String // true
c instanceof String // true
Object.prototype.toString.call(b); // "[object String]"
Object.prototype.toString.call(c); // "[object String]"

一般不直接使用封装对象,但是他们偶尔也会派上用场

拆封

如果想得到封装对象里面的值,可以使用valueOf函数,隐式拆封也是调用了valueOf函数:

1
2
3
4
5
6
7
8
9
10
var a = new String("abc")
var b = new Number(11)
var c = new Boolean(true)
a.valueOf() // "abc"
b.valueOf() // 11
c.valueOf() // true
var d = a + "";
console.log(d) // "abc"
typeof a // "object"
typeof d // "string"

原生函数作为构造函数

四种方式创建应该尽量避免构造函数,除非十分必要

  • array 数组
  • object 对象
  • function 函数
  • RegExp 正则表达式

    ARRAY(..)

    调用Array构造函数时,可以不需要加上new,效果一致。)且Array构造函数纸袋一个数字作为参数的时候,这个参数会当作数组的预设长度,而不是充当其中的一个元素
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 效果一致
    var a = new Array(1,2,3);
    a // [1,2,3]
    var b = Array(1,2,3)
    b // [1,2,3]
    var c = [1,2,3]
    c // [1,2,3]
    // 不同方式创建出来空数组效果不一致
    var d = new Array(3);
    console.log(d) // chrome上: (3) [empty × 3]
    d.length // 3
    var e = [undefined,undefined,undefined];
    console.log(e) // (3) [undefined, undefined, undefined]
    var f = []
    f.length = 3;
    console.log(f); // chrome上: (3) [empty × 3]
    // 直接以,创建。虽然长度是3令人费解,但是可以更好的复制粘贴
    var g = [,,,]
    console.log(g) // chrome上: (3) [empty × 3]

由于创建方式不同,导致在chrome下不一致的显示,但是更难过的是,他们有时相同,有时呵呵

1
2
3
4
5
6
var a = new Array(3)
var b = [undefined,undefined,undefined]
a.join("-") // "--"
b.join("-") // "--"
a.map(function(v,i){return i}) // (3) [empty × 3]
a.map(function(v,i){return i}) // [0, 1, 2]

a.map之所以执行失败,是因为a中是没有元素的,而b里面有undefied。
而join首先假定数组不为空,然后通过length属性值来便利其中的元素,而map并不做这种假定
可以通过这种方式来创建包含undefined单元的数组

1
2
var a = Array.apply(null, {length:3});
console.log(a) // (3) [undefined, undefined, undefined]

PS:永远不要创建和使用空单元数组

OBJECT、FUNCTION、REGEXP

除非玩不得已,尽量不要使用他们

1
2
3
4
5
6
7
8
9
10
var c = new Object();
c.foo = "bar";
c // {foo:"bar"}
var d = {foo:"bar"}
d // {foo:"bar"}
var e = new Function("a","return a * 2");
var f = function(a){return a*2};
function g(a){return a*2}
var h = new RegExp("^a*b+","g");
var i = /^a*b+/g

javascript对常量形式的代码会对他们进行预编译和缓存!

DATE、ERROR

相较于其他原生构造函数,Date、Error的用处比其他的更多,因为没有其他对用的常量形式来作为他们的替代
引入生成当前时间戳,使用

1
2
3
4
Date.now()
// 使用new来生成时间
new Date()
// Thu Jan 04 2018 06:47:59 GMT+0800 (CST)

错误对象通常与throw一起使用

1
2
3
4
5
6
function foo(x){
if(!x){
throw new Error("///");
}
// -
}

SYMBOL

Symbol可作为私有属性是一种简单标量基本类型

强制类型转换

抽象值操作

如果对象有自己的toString()方法,字符串化就会调用该方法并使用其返回值。
数组的默认toString方法经过了重新定义

1
2
var a = [1,2,3]
a.toString() // "1,2,3"

JSON 字符串化

JSON.stringify(42) // “42”
JSON.stringify(“42”) // “”42””
JSON.stringify(null) // “null”
JSON.stringify(true) // “true”

JSON.stringify()在对象中遇到undefined、function和symbol时会自动将其忽略,在数组中则会返回null

1
2
3
4
JSON.stringify(undefined)			// undefined
JSON.stringify(function(){}) // undefined
JSON.stringify([1,undefined, function(){},4]) // "[1,null,null,4]"
JSON.stringify({a:2, b: function(){}}) // "{"a":2}"

循环引用会出错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var o = {};
var a = {
b:42,
c:o,
d:function(){}
}
o.e = a
JSON.stringify(a)
a.toJSON=function(){
return {b:this.b}
}
JSON.stringify(a)
# Uncaught TypeError: Converting circular structure to JSON
# at JSON.stringify (<anonymous>)
# at <anonymous>:8:6

2017饿了么前端交流会

发表于 2017-11-06

几个演讲

从h5的埋雷到ServerLess,确实有很多收获。
从h5里面,不仅得到了关于页面优化的一些方案,也触及到了一些解决方案。发现h5有很多东西值得深究,有页面调试的一些优化等等。例如:从sticky到z-index实在有太多的学问了。而在工具方面,发现chrome的调试工具是在是太强大了,以前一直没有用过的memery和apperance等等,都有了新的认识。发现页面优化不仅仅是想象的那么简单。从小东西上入手,发现有很多的学问。是在是可以多学。层的探讨、强制同步布局、visibility、¥和&yen,以及dom的一步步呈现。感觉自己学的尚浅,有许多东西可以去学习。
从第三方服务上也学到许多,vue的地图篇,地图的实现以及地图api的调用以及api的设计,等等。对vue的深度似乎多了那么一些,总感觉自己学的东西都特别浅,没有能直接做的,对这一块还是得加深学习。
当然还有页面编辑可视化的一些小理解。可以通过直接编译组建,上传到服务器,然后服务器直接加到代码中,就可以不用cv代码,直接到里面去修改了。页面编辑其实就将页面上的东西图片生成一个json,让后到服务器中再呈现。而各个小组件是直接编译也好或者源代码也好,上传到服务器后,服务器上有一个gulp或者webpack,直接将其打包,编译,出现页面。这样就可以直接在本地做小组件,然后上传到服务器,服务器直接将其打包之后,就可以直接生成新的页面了。
还有用户体验。在用户体验上,发现确实有很多东西需要去深入。比如用户体验的的最终目的,用户体验的原始需求,去发觉里面的各个种种原始目的、需求去解决问题。这样能快速的从用户的角度去看事情的原委。当然,这个产品针对人群也要去探讨,是不是要更改是从目的人群去发掘的。
再就是vue和typescript。之前一直不愿意去接触typescript,很大的一个原因是因为自己喜欢原生的东西,喜欢纯粹的东西,所以不愿意,或者说去排斥typescript。这次无疑是打开了我对typescript的一扇门,因为typescript确实设计的很好,一些东西确实可以去深究。而typescript和vue也开始慢慢融合了,在vue的2.5版本里面是typescript的一个上升期,vue对typescript的支持,也可以更优雅的写vue了。所以对typescript也没有了之前的排斥,而是对它开始慢慢接受了。
最后的东西就是serverless,serverless是一个很强的东西,虽然我之前没有了解过,唯一了解是通过这次开发者大会上。但是serverless从前辈的介绍上,他确实可以减少很多运维和后端的一些成本,从而快速开发。现在这个时代就是一个快速开发的时代,所以对serverless的前景,肯定是光明的。所以开始使用serverless是一个不错的选择。
ele-taking

心得

在这次前端开发者大会上,确实有很多收获,从打开一扇新技术的大门,到很多新型技术上的接触。从一些排斥,到一些闪光点的发觉。慢慢发现还有很多事情应该去深究的。当然这是技术上的发觉。还有是在上海这个地方,或者说人生观的觉悟。上海这个地方是一个神奇的地方,他是金融中心,也是很多人的发源地。可以有很多机会让你一夜暴富。但是相同的,他太多的泡沫。很多人都是很疲惫的生活着,没有自己的梦想,在一个大城市的打磨之下,变成了这个大城市运作的一个个小零件。对这件事情之上,有很深的体会。路上的人看起来没有那么慈眉善目,也没有很多的暖,只是冷冷的互相看着手机。可能我是不适合上海这个城市吧。对于这种束缚力过强的地方,不如在小城市来的实在。

感谢

此次饿了么活动是子健学长和成成学长两个人推荐去的。在去的途中,子健学长和成成学长对我们非常照顾,不仅定房间和吃饭问题,在此次大会上也交流了许多技术,学到了很多。女神也对我们十分照顾,请我们大吃一顿,聊了很久,对于上海这个城市有了新的认识。在此次饿了么之旅发现了许多新技术,以及之前没有涉及到的领域,也从各个大牛手上获取了一手的咨询。不论是对自己,还是对家园,都有了新的认识,新的期许。

家园校友会--家园人回家

发表于 2017-10-30

写在前面

看到以往的学长学姐风风火火的从世界各地赶到家园参加这次举办的家园校友会,感触良多。多年后的自己能否会和他们一样,早早实现财务自由,为自己的青春年华的付出,再次奉献一份力呢?看到南昌大学家园网,再到现在的南昌大学家园工作室,变了种种种种。可是家园人回家探亲的那一刻,他们依然把这里当作家,熟悉感依然在。也希望若干年后的我,能为家园奉献这一份力。

家园校友会的成立

家园校友会在昨天成立了。听了好多关于他为什么成立的版本,出于行政上,出于物资上,出于情感上。可能各个方面的建设不一样,或者说在各个层面的位置看到它成立的作用不一样。但是我还是觉得不应该用一种负面的态度去看待整件事情。作为家园人,应该以一种纯粹的态度去看待它,认为家园校友会的成立就是为了帮助我们家园工作室更好的发展,利用之前的学长学姐的资源,让家园人更好的去发展,仅此而已。虽然作为中心组的管理层,但是我觉得家园是一个家,没必要从一种政治上的角度去考量证件事情。所以对于我个人而言,家园校友会的成立会为了我们家园人的发展,作出更好的贡献,让家园人变得更好。也是家园人凝聚的一种实力。

和学长的聊天

提问环节

讲真,在整天的聊天过程之中,最大的收获是和汪涛学长聊天了。在我向大家提问过人工智能这一个话题之后,汪涛学长对于这个话题有一些很深刻的认识。他认为我们目前的人工智能还是处于搬砖的弱人工智能,对于今后还有很大的提升。还有人工智能的高层是数学家玩的,并不是我们常人能够去接触的。听到这里,心里震惊了一下,虽然很失望,但是对人工智能有了一定的了解。也对腾讯这个公司有了一定的了解。

单对单的talking

学长从主教302(我们开座谈会的地方)到机房和我们聊天,我单独和学长聊了聊工作室的基本情况,工作室面临的问题。他对工作室的现状虽然没有表现出堪忧的态度,但是对工作室的体制化,制度化表示了一些质疑。他告诉我说制度这种东西,有好处也有坏处。好处是大家能够更规范的去做事情,但坏处就是它没有之前那么纯粹,磨灭了大家对执着技术的热情。当然,技术的热情确实从历届学长学姐的眼里,我们确实没有以前那么高了。可能一味的追求某种东西,到最后就忘了自己的初衷。而家园研发在我手上,希望让他更强大,更和以前那么纯粹。因此我极度期望去改革,去把事情变得纯粹一些。关于技术问题,我们的技术确实存在某些弊端,比方说对将来要工作或者其他考量。我感觉,现在是把工作室的地位降低,而不是纯粹的追求技术,我们确实把自己当作一个工厂,一个去造就名企名业的工厂,只是一个免费的培训机构而已。而这件事情我们确实需要重新审视一下自己。技术上:学长认为python是入门级,轻量化的一个东西,可以作为快速开发,快速看创造出的原型,而java和c#作为两门很好的语言,去琢磨它,去吃透它,是整个大学的必修课。也是作为到社会之后快速学习的一种手段,或者说一种桥梁。因此对于java和python,我的意图是重学,甚至作为整个大组的基准,去学习。整个研发在我接手那一刻,发现确实存在一些问题,例如大家很少来机房,在技术上只是作为工厂者在创造名企。而整个工作室确实少了一些像家的感觉,等等。也期望大家能多学一些,然后多去用,多去创造吧。是真正想因为技术在一起的。

写在最后

说实话,昨天是我从大学到现在以来,第一次和这么多大佬一起相聚,有腾讯基础架构师,现在在做人工智能,有原迅雷的cto,现在在做大数据,也有针对外企的汪涛学长,一直在很努力的尝试不同种类的coding;有政界大牛,也有商界大咖,coding界的佼佼者……真心感觉自己很菜,自己还需要学习更多。从第一届家园人中看到更多希望和期许,从历届的家园人中看到友谊天长地久的长存,感觉良多。发现我们不仅仅是一个社团组织,而是更是一群追梦人,为了纯粹的技术,为了纯粹的事情聚在一起。家园就是期望和家一样,越来越好。而公司化or社团化,体制化or自由化,应该就不言而喻了吧。

DPCH (DPCHCD)服务器的搭建与应用

发表于 2017-10-21

什么是DHCP?

1.DHCP简介

DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户机能够利用这个IP上网。

2.为什么要使用DHCP?

DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)通常被应用在大型的局域网络环境中,主要作用是集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。

3.DHCP实现

dhcp_client
DHCP的实现分为4步,分别是:
第一步:Client端在局域网内发起一个DHCP Discover包,目的是想发现能够给它提供IP的DHCP Server。
第二步:可用的DHCP Server接收到Discover包之后,通过发送DHCP Offer包给予Client端应答,意在告诉Client端它可以提供IP地址。
第三步:Client端接收到Offer包之后,发送DHCP Request包请求分配IP。
第四步:DHCP Server发送ACK数据包,确认信息。

#### 4.安装DHCP服务器
由于我使用的系统是archlinux,因此在我bash中之存在dhcpcd,当然他们是同名。
使用如下命令安装

1
pacman -S dhcpcd

检测是否安装成功,键入如下命令

1
2
3
4
5
dhcpcd --version
//显示如下。。。代表安装成功
dhcpcd 6.11.5
Copyright (c) 2006-2016 Roy Marples
Compiled in features: INET IPv4LL INET6 DHCPv6 AUTH

5.DHCP服务器的一般配置

dhcp服务器一般配置步骤

1、dhcp服务器住配置文件dhcpd.conf,制定ip作用域,制定分配一个或多个ip地址范围
2、建立租约数据库文件
3、重新加载配置文件或重启dhcp服务器

dhcp的工作流程

在翻阅其他人的博客中,发现这个哥们的博客写的很好,因此引用过来

配置文件DHCPD.CONF

由于我的系统是archlinux,因此自动生成了一个dhcpd.conf文件在/etc目录之下。下面看一个完整的dhcpcd.conf:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
vim /etc/dhcpd.conf 
# dhcpd.conf
#
# Sample configuration file for ISC dhcpd
#
# option definitions common to all supported networks...
option domain-name "example.org";
option domain-name-servers ns1.example.org, ns2.example.org;
default-lease-time 600;
max-lease-time 7200;
# Use this to enble / disable dynamic dns updates globally.
#ddns-update-style none;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
#authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
# No service will be given on this subnet, but declaring it helps the
# DHCP server to understand the network topology.
subnet 10.152.187.0 netmask 255.255.255.0 {
}
# This is a very basic subnet declaration.
subnet 10.254.239.0 netmask 255.255.255.224 {
range 10.254.239.10 10.254.239.20;
option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
}
# This declaration allows BOOTP clients to get dynamic addresses,
# which we don't really recommend.
subnet 10.254.239.32 netmask 255.255.255.224 {
range dynamic-bootp 10.254.239.40 10.254.239.60;
option broadcast-address 10.254.239.31;
option routers rtr-239-32-1.example.org;
}
# A slightly different configuration for an internal subnet.
subnet 10.5.5.0 netmask 255.255.255.224 {
range 10.5.5.26 10.5.5.30;
option domain-name-servers ns1.internal.example.org;
option domain-name "internal.example.org";
option routers 10.5.5.1;
option broadcast-address 10.5.5.31;
default-lease-time 600;
max-lease-time 7200;
}
# Hosts which require special configuration options can be listed in
# host statements. If no address is specified, the address will be
# allocated dynamically (if possible), but the host-specific information
# will still come from the host declaration.
host passacaglia {
hardware ethernet 0:0:c0:5d:bd:95;
filename "vmunix.passacaglia";
server-name "toccata.example.com";
}
# Fixed IP addresses can also be specified for hosts. These addresses
# should not also be listed as being available for dynamic assignment.
# Hosts for which fixed IP addresses have been specified can boot using
# BOOTP or DHCP. Hosts for which no fixed address is specified can only
# be booted with DHCP, unless there is an address range on the subnet
# to which a BOOTP client is connected which has the dynamic-bootp flag
# set.
host fantasia {
hardware ethernet 08:00:07:26:c0:a5;
fixed-address fantasia.example.com;
}
# You can declare a class of clients and then do address allocation
# based on that. The example below shows a case where all clients
# in a certain class get addresses on the 10.17.224/24 subnet, and all
# other clients get addresses on the 10.0.29/24 subnet.
class "foo" {
match if substring (option vendor-class-identifier, 0, 4) = "SUNW";
}
shared-network 224-29 {
subnet 10.17.224.0 netmask 255.255.255.0 {
option routers rtr-224.example.org;
}
subnet 10.0.29.0 netmask 255.255.255.0 {
option routers rtr-29.example.org;
}
pool {
allow members of "foo";
range 10.17.224.10 10.17.224.250;
}
pool {
deny members of "foo";
range 10.0.29.10 10.0.29.230;
}
}

可以看到如上默认配置
配置格式如下

1
2
3
4
5
6
# 全局配置
参数或选项 // 全局生效
#局部配置
声明 {
参数或选项 // 局部生效
}

常用参数介绍

我在其他人博客看到常用参数说明,于是就拷贝下来
dhcp_config1
dhcp_config2
dhcp_config3

配置实例

某单位销售部有80台计算机所使用的IP地址段为
192.168.1.1-192.168.1.254,子网掩码为255.22.255.0,网关为
192.168.1.1,192.168.1.2-192.168.1.30给各服务器使用,客户
端仅可以使用192.168.1.100-192.168.1.200。剩余IP地址保留。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
subnet 198.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1;
option subnet-mask 255.255.255.0;
option nis-domain "domain.org";
option domain-name "domain.org";
option domain-name-servers 192.168.1.2;
option time-offset -18000;
option netbios-node-type 2;
range dynamic-bootp 198.168.1.100 192.168.1.200;
default-lease-time 43200;
host ns {
next-server archlinux.org;
hardware ethernet ...;
fixed-address ...;
}
}

开启服务器
1
systemctl start dhcpcd
关闭服务器
1
systemctl stop dhcpcd

你不知道的javascript————this和对象原型

发表于 2017-09-06

this误解

从字面意思来看,this貌似是指向自身的.因此出现各种各样的误解.

指向自身

先看一个demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function foo(num) {
console.log("foo: " + num);
this.count++;
}
foo.count = 0;
var i;
for (i = 0; i < 10; i++) {
if(i > 5) {
foo(i)
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
console.log(this.count) // NaN

从上述例子中,可以很清楚的看到函数被调用了四次,而为什么打印出来的this.count是NaN呢?显然this指向的count并不是函数的count.的确在foo.count=0的时候给对象foo加了一个count,但是内部代码this.count却不是指向的那个函数对象.从第二章的理解当中,不难发现,其创建了一个全局count,并且它是NaN.

this是什么?

this是在运行时绑定的,并不是在编写时绑定的.他的上下文取决于函数调用时的各种条件,this绑定和函数声明没有任何关系,取决于函数的调用方式.

当一个函数被调用时,会创建一个活动记录(有时候称之为上下文).这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数信息,而this就是这个记录的一个属性。会在函数执行过程中用到。

PS:说白了,THIS实际上是在函数调用时发生的绑定,他指向什么完全取决于函数在哪里被调用。

调用位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function baz() {
// 当前作用栈是: baz
// 因此调用位置是全局作用域
console.log("baz")
bar() // <-- bar的调用位置
}
function bar() {
// 当前调用栈是baz -> bar
// 因此调用位置是baz中
console.log("bar")
foo(); // <-- foo的调用位置
}
function foo() {
// 当前调用栈是baz -> bar -> foo
// 当前调用位置在bar中
console.log("foo")
}
baz() // <-- baz的调用位置

从上述调用栈,可以分析出真正的调用位置,他决定了this的绑定

四种绑定规则

默认绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function foo() {
console.log(this.a)
}
var a = 2;
foo(); // 2
///////////////////////
function foo2() {
"use strict"
console.log(this.a)
}
var a =2
foo2() // typeerror
////////////////////////
function foo3() {
console.log(this.a)
}
var a =2
(function () {
"use strict"
foo3() // 2
})()

在非严格模式下,foo的调用默认指向调用位置,例子中是全局,而在严格模式下会抛出异常,在严格模式调用其他位置的this,也可以调用。

隐式绑定
1
2
3
4
5
6
7
8
function foo() {
console.log(this.a)
}
var obj = {
a : 2,
foo : foo
}
obj.foo // 2

在代码中,foo默认是绑定在obj的foo的属性上,因此隐式的把foo中的this绑定在obj之上,调用的也是obj中的a

1
2
3
4
5
6
7
8
9
10
11
12
function foo() {
console.log(this.a)
}
var obj2 = {
a:42,
foo:foo
}
var obj1 = {
a: 2,
obj2: obj2
}
obj1.obj2.foo() // 42

在上面的代码中,经过多层的调用,但是最终结果还是指向的是最后一层调用的位置。因此可以的出结论。在对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。

隐式丢失
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
// 隐式丢失,成为默认绑定
function foo() {
console.log(this.a)
}
var obj = {
a:2,
foo: foo
}
var bar = obj.foo
var a = "this is global"
bar() // this is global
////////////////////////////////////////
// 回调的隐式丢失
function foo() {
console.log(this.a)
}
function doFoo(fn) {
// fn其实引用的是foo
fn() // 调用位置
}
var obj = {
a: 2,
foo: foo
}
var a = "this is global"
doFoo(obj.foo) // this is global

虽然bar是obj.foo的一个引用,但实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此引用了默认绑定。
第二种情况也是如此,在回调时的隐式丢失导致的问题
这也导致setTimeout中的隐式丢失,常用方法是将this绑定到一个变量中,这样就不会导致隐式丢失

显式绑定

使用call,和apply方法绑定。
1、硬绑定

1
2
3
4
5
6
7
8
9
10
11
12
function foo() {
console.log(this.a)
}
var obj = {
a:2
}
var bar = function () {
foo.call(obj)
}
bar() // 2
setTimeout(bar, 100) // 2
bar.call(window) // 2

无论是强制显示调用window,他都是2.因为在bar这个函数中调用了foo.call(obj),最终都会绑定到obj上。为了硬绑定的应用,ES5中有bind方法,专门用于绑定。

API调用的“上下文”
和bind一样,他的作用是保证回调

1
2
3
4
5
6
7
function foo(el) {
console.log(el, this.id)
}
var obj = {
id: "awesome"
}
[1, 2, 3].forEach(foo, obj) // 调用时将this绑定到obj上

new 绑定
使用new来调用函数,会自动执行以下操作:
1、创建一个全新的对象
2、这个新对象会被执行[[Prototype]]连接
3、这个新对象会绑定到函数调用的this
4、如果函数没有返回其他对象,那么new表达式中的函数中会自动调用这个对象

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
function foo(a){
this.a = a
}
var bar = new foo(2)
console.log(bar.a) // 2
```
_ps:优先级------>new绑定>显示绑定>隐式绑定>默认绑定_
### 判断this
1、函数是否在new中调用(new绑定)?如果是的话this绑定是新的对象
2、函数是否通过call、apply(显示绑定)或者硬绑定的调用?如果是的话this绑定的是制定对象
3、函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定到那个上下文对象中
4、如果都不是的话,使用默认绑定,在严格模式下,就绑定到undefined上,否则绑定到全局对象上。
##### 例外
```bash
function foo(){
console.log(this.a)
}
var a = 2
foo.call(null) // 默认绑定
///////////////////////////////////
// 科里化
function foo(a, b) {
console.log("a:" + a +" , b: " + b)
}
foo.apply(null, [2,3]) // a:2,b:3
var bar = foo.bind(null, 2)
bar(3)
///////////////////////////////////
// 间接引用
function foo() {
console.log(this.a)
}
var a = 2
var o = {a:3, foo: foo}
var p = {a:4}
o.foo() // 3
(p.foo = o.foo)() // 2
// 复制表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo或者o.foo

对象

在string中,本身的字符串“I am a string”并不是一个对象,而是一个字面量,在使用了对象的方法之后,javascript会自动将其转换成一个string对象
null和undefined没有对应的构造函数,他们只有文字形式。相反,Date只有构造函数,没有文字形式。
对于Object,Array,Function和RegExp来说,无论是文字形式还是构造形式,他们都是对象不是字面量。

你不知道的JavaScript————作用域和闭包篇

发表于 2017-08-19

编译原理

为什么要把这个放在重点呢?因为每门语言的最底层,那就是编译成机器语言了。了解编译原理。对理解语言的特殊现象有很大帮助。
先说说其他非脚本语言开始到结束。我在之前的计算机系统基础的篇目中学到C的编译。变成汇编语言之后,每个函数名字,每个变量名字,都会写入到一张表里面。而这张表,是将所有的变量放置在一起。查找匹配相应的变量,并寻找其变量地址。
应该是所有的语言都是相似的。在了解过javascript编译原理之后。发现这很多相似的地方。

分词/词法分析

将字符组成的字符串分解成有意义的代码块,代码块统称为词法单元
例如:在 var a = 2。将会分解成 var, a, =, 2

解析/语法分析

这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表程序语法结构的树(抽象语法树)。
例如:var a = 2这个代码中,他可能有一个父节点,其本身节点a,其值为2

代码生成

将抽象语法树转换成可执行代码的过程统称为代码生成。
例如:var a = 2,创建一个a的变量,并且储存一个值为2在a中

ps:javascript中远复杂的多,在语法分析和代码生成阶段有特定性能进行优化。一般而言,javascript为了保证高效的执行代码,通常是函数片段执行钱然后进行编译。以保证代码性能的最佳

作用域理解

引擎、编译器、作用域。作用域的理解并不是那么简单。他包含引擎的查询执行,以及编译器编译。

编译器的处理

首先,编译器遇到var a,编译器会询问同一个作用域的集合中是否存在该变量。如果是,编译器会忽略该声明, 继续编译。否则它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为a。
接下来,编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫作a的变量。如果是,引擎就会使用这个变量;如果否,引擎会继续查找该变量(从作用域链中)。如果引擎最终找到了a变量,就会将2赋值给它。否则引擎就会举手示意并抛出一个异常!
总结:变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值。也正因为赋值是分开的。将var a和赋值2分开执行,才会导致后面的变量提升

左值(LHS)与右值(RHS)

从字面来看,有左值和右值之分。所谓左值,在等号的左侧;所谓右值,就在等号的右侧。即:左侧是被赋值,右侧是查询。当然,所有的查询都可以当作一次右值(至少我是这么理解的)。
而引擎和作用域则是如下工作的:
以下面为例

1
2
3
4
function foo (a) {
console.log(a)
}
foo(2)

1、引擎查询作用域中是否有foo
2、作用域查询到foo地址,将地址传给引擎
3、引擎执行foo,并查询作用域中是否有a
4、作用域查到a的地址,将其传给引擎
5、引擎给a赋值,并查询作用域中是否有console
6、作用域查到console地址,将其传给引擎
7、引擎使用console,并查询其log方法,并且查询作用域中的a是否改变
8、作用域查询a的值
9、引擎使用console.log方法,并将a的值传入

ps:1、正因为是直接从当前作用域开始查询,所以会有作用域屏蔽,当前作用域的变量会屏蔽上层同名变量。2、因为函数声明中,其名称也是变量,也导致了同一个作用域中后者函数会覆盖掉前者函数。3、所谓的作用域就是建表,当前作用域下所有的变量都会存入表中。待查询需要,直接查表即可。4、未声明的变量,查表后未发现变量,会抛出引用错误

欺骗词法

这是一种在运行时“修改”作用域的词法。因此也叫欺骗词法

EVAL
1
2
3
4
5
6
function foo (str, a) {
eval(str) // 欺骗……
console.log(a, b)
}
var b = 2
foo("var b = 3, 1")

eval的作用是将字符串转化成可执行的代码块。因此在执行eval代码时,前面的代码是以动态的插入进来的,达到词法作用域的修改。在严格模式之下,eval在运行时有自己的词法作用域,因此意味着在声明中无法修改所在的作用域。

SETTIMEOUT

setTimeout第一个参数也是可以传入一个字符串。他将会默认将字符串转化成代码快。这种虽然稍微更安全一些(不会修改)但是也是要少用。避免使用

ps: 上述两者都有性能问题。由于在预编译时,javascript将所有的变量进行提升,在代码执行前写入作用域,大多数都是在函数执行前进行编译。而使用上述两种情况之后。由于无法确定当前作用域中是否有该种情况,于是将不会进行编译。而是在当前代码块执行编译的时候,才会进行作用域的写入,调节。这种情况将所有的javascript代码,引擎无法进行优化,因此性能极低。所以不推荐使用

WITH

在严格模式之下使用报错。不推荐使用。

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
// 好处
var obj = {
a:1,
b:2,
c:3
}
// 赋值很麻烦
obj1.a = 2
obj1.b = 3
obj1.c = 4
// 赋值相对快捷
with(obj) {
a = 3
b = 4
c = 5
}
// bad use
function foo(obj) {
with(obj){
a = 2
}
}
var o1 = {
a:3
}
var o2 = {
b:3
}
foo(o1)
console.log(o1.a) // 2
foo(o2)
console.log(o2.a) // undefined
console.log(a) // 2

出现上述原因是什么?
在非严格模式中,第一种情况o1出现的原因是因为在当前作用域之下有a的这个属性,因此将a赋值过去。
第二种情况是因为由于o2中并没有找到a这个属性,而出现一种左值赋值操作。因此将a赋值给2,而a在非var情况之下赋值,变成全局变量出现。

javascript在es6之前除try-catch没有块级作用域

什么是块级作用域?之前我有写过一篇文章。
所谓块级作用域就是在打括号的包裹之下,里面的变量不外泻。即:

1
2
3
4
{
var a = 0
}
console.log(a) // 0

能在外部访问到的,都不是块级作用域。
因此在es5之前,对于变量的使用,都要尽可能的使用var来达到变量不会冲突的情况。不然很可能使用到上一级的变量,导致出错。

ES6中的LET

出现let之后,便有了块级作用域。这种情况为javascript更容易

提升

文章之前也提到过。由于变量在引擎中是一个先写入作用域中,再将变量赋值的一个过程。所以有奇妙的提升。
例如:

1
2
3
4
foo()
function foo () {
console.log('hello')
}

在其他语言中,这样写代码是会报错的,但是在javascript中则不会。因为函数声明中,函数名称是一个变量。函数表达式则不会。在首先代码编译阶段,foo函数首先被提升到作用域中->然后执行代码。foo函数->引擎中发现作用域中有foo函数->引擎执行foo函数

闭包

闭包是为了函数外部使用函数内部变量,出现的一个名词

1
2
3
4
5
6
7
8
9
function foo() {
var a = 2;
function bar () {
console.log(a)
}
return bar
}
var baz = foo()
baz() // 2

这种就是闭包。闭包的详细,之前重读javascript一书中有写过。
ps: 所有的javascript的回调都是闭包

模块机制

之前使用模块机制,是框架中代码写入的。而现代机制使用commonjs的规范使用的。

小结:

学习到javascript第一章之后,发现很多javascript的一些现象可以通过底层来解释,真是太棒了!很开心的学玩了这一章节,明白了性能问题出现的原因,以及词法作用域的底层原理。还有javascript代码的执行。不禁感叹v8引擎的强大,对javascript的优化简直棒极了!对深入学习javascript又更上一层楼

2017暑期留校有感

发表于 2017-08-04

一年一度的暑期留校就这样结束了。
去年忘记总结,今年一定要总结。

回顾这一个月。我问自己学到了什么。

1、从最开始的javascript。重读了一遍,发现要学习的东西还有很多。比如对象以及数组。依然得深挖。重读javascript对我在工作中帮助很大,让我发现许许多多js的新用法,精用法。
2、这个月我也开始学习了http,入门http开始明白什么是http,为什么要用http,认识了http,以及http的简单用法,以及其规范。明白了三次握手,以及四次挥手的意义。以及https的原理。(比如前几天的赛门铁克的证书问题)
3、学习nodejs,mongodb,由于重读了javascript,我开始学习nodejs以及mongodb。开始接触了一个小的项目,有关于消费查询。虽然不是自己写的,却对项目目录,以及项目重构有了一定的看法。
4、项目经验。回答了新生的几个入门项目以及大型项目云家园的开发。面对大型项目的前端开发,确实有许许多多的问题,比如项目的冗余,以及项目的优化。多人合作问题等等。发现了大型项目的协作困难,以及了解了其流程开发。

生活上的感谢信

很感激因为我手术原因照顾我的朋友们。
首先是显林,由于手术原因,一直很照顾我。给我占座,给我带东西,帮我修bug,教我很多东西。整个暑期留校都有他的协助,真的很感激……可惜的是因为太忙所以下学期大多是不能留校了。在机房就没有几个大三的人了。
其次是谢总,在生活上,我住他的寝室,平时也给我带很多吃的,带我去健身房,对于这身膘,他可是功不可没……每天在寝室看他和小姐姐聊天真是很无奈
然后是可芹,在我中暑的时候给我霍香正气水,虽然很难喝,很难入口,但是这份情谊,铭记于心。生活上带我玩游戏,两个人互黑,冒着女朋友吃醋的风险,和她聊天,也是没谁了。
小黑,一个女装大佬的存在,小黑真的是在生活中很平易近人的。帮我调verynginx,以及服务器。这份情谊实在深沉。
还有老田,老田真的很强,帮我装arch,十几分钟就能从一个什么都没有的系统出现一个带有界面的linux,是在强大。对于调试方面,简直是大佬的存在
最后还有大家,大家的在暑期留校里面,都提升了很多,对大家都了解了很多,在能力上大家都有提升,在情感上大家都增进了情感,了解了更多彼此。很感激此次的暑期留校。能让我看到不一样的家园工作室!

初识http

发表于 2017-08-01

初识http

在刚刚开始学习前端ajax时,经常听说http协议,“不就是三次握手,四次挥手吗?”,一番言语过后。似懂非懂。近期由于开始学习nodejs,借此机会开始学习了一波http

什么是http?

从其英文全意来看,是HyperText Transfer Protocol,中文解释是超文本传输协议。那什么又是超文本?。在wiki上解释是:

超文本(英语:Hypertext)是一种在电脑显示器或其他电子设备,用以显示文本及与文本相关的内容,其中的文字包含有可以链接到其他字段或者文档的超链接,允许从当前阅读位置直接切换到超链接所指向的文字。万维网的架构便是以超文本的底层概念定义为基础。

因此,从概念上来看,http最初的目的就是为了提供一种发布和接收HTML页面的方法。

http包含了那些方法?

HTTP/1.1协议中共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源:

GET

向指定的资源发出“显示”请求。使用GET方法应该只用在读取数据,而不应当被用于产生“副作用”的操作中,例如在Web Application中。其中一个原因是GET可能会被网络蜘蛛等随意访问。参见安全方法

HEAD

与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。

POST

向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。

PUT

向指定资源位置上传其最新内容。

DELETE

请求服务器删除Request-URI所标识的资源。

TRACE

回显服务器收到的请求,主要用于测试或诊断。

OPTIONS

这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用’*’来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。

CONNECT

HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。
方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed),当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)。
HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。当然,所有的方法支持的实现都应当匹配下述的方法各自的语义定义。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。例如:

PATCH(由 RFC 5789 指定的方法)

用于将局部修改应用到资源。

一般来说,我们常用的有GET,POST,DELETE,PUT四个方法。大多数情况用于获取,增改,删除以及传输文件。

http包含那些内容?

大体上,包含报文首部,报文主体。

报文首部

报文首部由于请求以及响应的报文首部。

请求报文首部。

请求行:包含用于请求的方法,请求URI以及HTTP版本
首部字段:包含表示请求和响应的各种条件和属性的各类首部。一般有四种首部,分别是:请求首部、响应首部、通用首部以及实用首部
其他:可能包含HTTP里为定义RFC的首部(Cookie等)

响应报文首部

状态行:包含表明结果的状态码,原因短语和HTTP版本
首部字段:包含表示请求和响应的各种条件和属性的各类首部。一般有四种首部,分别是:请求首部、响应首部、通用首部以及实用首部
其他:可能包含HTTP里为定义RFC的首部(Cookie等)

报文主体

报文主体和报文首部是分开的。由换行分开报文首部以及报文主体。

返回结果的常用HTTP状态码
状态码类别原因短语
1xxInformational(信息性状态码)接受的请求正在处理
2xxSuccess(成功状态码)请求正常处理完毕
3xxRedirection(重定向状态码)需要进行附加操作以完成请求
4xxClient Error(客户端错误状态码)服务器无法处理请求
5xxServer Error(服务器端错误状态码)服务器处理请求出错

1XX 消息

这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于HTTP/1.0协议中没有定义任何1xx状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送1xx响应。

2XX 成功

200 Ok

请求已成功,请求所希望的响应头或数据体将随此响应返回。实际的响应将取决于所使用的请求方法。在GET请求中,响应将包含与请求的资源相对应的实体。在POST请求中,响应将包含描述或操作结果的实体。

204 No Content

服务器成功处理了请求,没有返回任何内容。

206 Partial Content

服务器已经成功处理了部分GET请求。类似于FlashGet或者迅雷这类的HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。

3XX 重定向

301 Moved Permanently

被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。
新的永久性的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
如果这不是一个GET或者HEAD请求,因此浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
注意:对于某些使用HTTP/1.0协议的浏览器,当它们发送的POST请求得到了一个301响应的话,接下来的重定向请求将会变成GET方式。

302 Found

要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
新的临时性的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
如果这不是一个GET或者HEAD请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
注意:虽然RFC 1945和RFC 2068规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将302响应视作为303响应,并且使用GET方式访问在Location中规定的URI,而无视原先请求的方法。因此状态码303和307被添加了进来,用以明确服务器期待客户端进行何种反应。

303 See Other

对应当前请求的响应可以在另一个URI上被找到,当响应于POST(或PUT / DELETE)接收到响应时,客户端应该假定服务器已经收到数据,并且应该使用单独的GET消息发出重定向。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。这个新的URI不是原始资源的替代引用。同时,303响应禁止被缓存。当然,第二个请求(重定向)可能被缓存。
新的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
注意:许多HTTP/1.1版以前的浏览器不能正确理解303状态。如果需要考虑与这些浏览器之间的互动,302状态码应该可以胜任,因为大多数的浏览器处理302响应时的方式恰恰就是上述规范要求客户端处理303响应时应当做的。

304 Not Modified

表示资源未被修改,因为请求头指定的版本If-Modified-Since或If-None-Match。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。

307 Temporary Redirect

在这种情况下,请求应该与另一个URI重复,但后续的请求应仍使用原始的URI。 与302相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个POST请求来重复POST请求。

4XX客户端错误

400 Bad Request

由于明显的客户端错误(例如,格式错误的请求语法,太大的大小,无效的请求消息或欺骗性路由请求),服务器不能或不会处理该请求

401 Unauthorized

用户没有必要的凭据。该状态码表示当前请求需要用户验证。该响应必须包含一个适用于被请求资源的WWW-Authenticate信息头用以询问用户信息。客户端可以重复提交一个包含恰当的Authorization头信息的请求。如果当前请求已经包含了Authorization证书,那么401响应代表着服务器验证已经拒绝了那些证书。如果401响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。

403 Forbidden

服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个HEAD请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,假如它不希望让客户端获得任何信息。

404 Not Found

请求失败,请求所希望得到的资源未被在服务器上发现,但允许用户的后续请求。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。

5XX服务器错误

500 Internal Server Error

通用错误消息,服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。没有给出具体错误信息。

503 Service Unavailable

由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是暂时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个Retry-After头用以标明这个延迟时间。如果没有给出这个Retry-After信息,那么客户端应当以处理500响应的方式处理它。

HTTP的应用

三次握手,四次挥手

哪三次握手?以一个小段子来解释。
第一次握手:A确定B是不是知道A喜欢他;问:‘你是不是喜欢我啊?’
第二次握手:B告诉A他很喜欢她,并且反问;答:‘我喜欢你啊,你喜欢我吗?’
第三次握手:A告诉B;说:‘我喜欢你啊,那我们在一起吧。。。’
于是他们就在一起了。
这就是经典的三次握手
那又是哪四次挥手呢?
第一次说:A告诉B她不喜欢他了;说:‘我已经不喜欢你了,我们分手吧。’
第二次说:B告诉A说也不喜欢她了;说:’我知道了,我也不喜欢你了,我们分手吧。‘
第三次说:A告诉B说他已经知道了:’我知道了,那我们分手吧。‘
第四次说:B告诉A说他已经知道了A的心意:’我知道了,那我们就分手吧。‘
于是他们因此分手。

为什么是三次握手呢?
在知乎上看到一个人这样答道:
这个问题的本质是, 信道不可靠, 但是通信双发需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足”在不可靠信道上可靠地传输信息”这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了.
为了满足数据的可靠性。因而才设置三次握手。我想,大概四次挥手也是这个原理吧

http有不满足现代web发展的需求?

http是上个世纪的产物,到达21世纪之后,http的功能已经捉襟见肘。因此,有了扩展的http,https。

什么是HTTPS

https并不是新型产物,而是http Secure,是更安全版本。在其基础上加了一层ssl层。用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司(Netscape)进行,并内置于其浏览器Netscape Navigator中,提供了身份验证与加密通讯方法。现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。

为什么要HTTPS

由于普通的http协议会经过多层代理服务器,因此可能在通讯过程中的数据的泄密和被篡改。也可能遭到非法入侵。因此,为了更好的用户保密,以及确定用户身份。有了ssl层。
ssl释义:
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
因此,ssl保证了http的安全性。也由于其多层的访问确认关系,要比正常的http慢2-100倍

总结:

初识http让我从前端思维到后端思维的一个过渡。逐渐解密在数据传输过程中的小黑匣。http状态码以及其工作原理也十分重要的体现在我日常工作中。后端的思维过渡以及前端的新层面让我了然于胸。初识http,重新认识了互联网。

1234
gdccwxx

gdccwxx

39 日志
16 标签
GitHub E-Mail
© 2017 — 2022 gdccwxx