目录
-
HTTPS
-
基本概念
- 单钥匙就是对称加密,对称加密的速度快
- 双钥匙就是非对称加密,非对称加密的速度慢
- 非对称加密的秘钥中,公开让别人知道的就是公钥
- 留在自己这里不让别人知道的就是私钥
- 公钥加密,私钥解密,这个叫加密
- 私钥加密,公钥解密,这个叫签名
-
简略过程
首先服务器让CA机构用私钥 J 加密自己的公钥 D,传给浏览器,这是私钥加密,公钥解密,防止公钥 D 在传输过程中被别人篡改。浏览器得到了公钥 D 之后,加密自己的对称加密的秘钥 M,传给服务器,这是公钥加密,私钥解密,这个目的是加密,为了让中间人不知道我的 M 是什么。
注:非对称加密的复杂度非常高,性能非常低,因此仅仅适合这个传递秘钥 M 的过程,数据量很小,而且仅仅一次。之后的传输,通过对称秘钥进行传输,对称加密的效率比非对称加密高出几个数量级。
-
正规示范——数字证书
在HTTPS中,数字证书是一种用于验证网站身份并加密通信的安全证书。数字证书由证书颁发机构(Certificate Authority,简称CA)签发,它包含了一组加密的数据,用于确认网站的真实性和可信性。当用户访问一个使用HTTPS的网站时,浏览器会接收并验证该网站的数字证书。
数字证书包含以下重要信息:
- 公钥:其中包含一个公开密钥,用于加密浏览器和服务器之间的通信。公钥是加密的,所以其他人无法解密数据,只有服务器拥有与公钥匹配的私钥,才能解密加密的数据。
- 网站信息:数字证书中包含有关网站的信息,如网站的名称(通常为域名),公司名称(如果是企业网站),所在地区等。这些信息用于验证网站的所有者
- 数字签名:证书颁发机构使用自己的私钥对证书信息进行数字签名,以保证证书的真实性和完整性。浏览器使用证书颁发机构的公钥来验证数字签名的有效性。
当用户访问一个使用HTTPS的网站时,浏览器会下载网站的数字证书并检查以下事项:
- 证书是否由受信任的证书颁发机构签发。
- 证书是否在有效期内。
- 网站的域名是否与证书中的域名匹配。
- 证书中的数字签名是否有效。
详见:http://t.csdn.cn/AaiYX
-
Javascrip的数组
Array是 JavaScript 的原生对象,同时也是一个构造函数,可以用它生成新的数组
Array()作为构造函数,行为很不一致(具体这不做解释)。因此,不建议使用它生成新数组,直接使用数组字面量是更好的做法(如下)。
var arr = [1, 2];
- 静态方法 Array.isArray()
Array.isArray方法返回一个布尔值,表示参数是否为数组。它可以弥补typeof运算符的不足,示例如下。
var arr = [1, 2, 3];
typeof arr // "object"
Array.isArray(arr) // true
- 实例方法
- 常用
方法 | 描述 |
concat() | 连接两个或更多的数组,并返回结果。 |
join() | 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。 |
pop() | 删除并返回数组的最后一个元素 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度。 |
reverse() | 颠倒数组中元素的顺序。 |
shih() | 删除并返回数组的第一个元素 |
slice() | 从某个已有的数组返回选定的元素,原数组的内容不变 |
sort() | 对数组的元素进行排序,该方法会改变原来的数组,而不会创建新的数组 |
splice() | 删除元素,并向数组添加新元素,数组的值会发生变化,两个参数时表示删除,三个参数时,第二个参数为0,表示添加元素到对应的位置 |
unshih() | 向数组的开头添加一个或更多元素,并返回新的长度。 |
toSource() | 返回该对象的源代码。 |
toString() | 把数组转换为字符串,并返回结果。 |
toLocaleString() | 把数组转换为本地数组,并返回结果。 |
valueOf() | 返回数组对象的原始值 |
- valueOf(),toString()——重点
- valueOf方法是一个所有对象都拥有的方法,表示对该对象求值。不同对象的valueOf方法不尽一致,数组的valueOf`方法返回数组本身。
var arr = [1, 2, 3];
arr.valueOf() // [1, 2, 3]
- toString方法也是对象的通用方法,数组的toString方法返回数组的字符串形式。
var arr = [1, 2, 3];
arr.toString() // "1,2,3"
var arr = [1, 2, 3, [4, 5, 6]];
arr.toString() // "1,2,3,4,5,6"
-
RegExp对象——正则表达式
JavaScript 的正则表达式体系是参照 Perl 5 建立的。
Perl 5是一种通用的高级编程语言,它是Perl编程语言家族中的一员。Perl最初由Larry Wall于1987年开发,Perl 5是Perl编程语言的第五个主要版本,于1994年发布。它是Perl编程语言的主要版本,并在很多方面得到广泛应用。
-
概述
- 新建正则表达式有两种方法。
- 一种是使用字面量,以斜杠表示开始和结束。
var regex = /xyz/;
- 另一种是使用RegExp构造函数。
var regex = new RegExp('xyz');
上面两种写法是等价的,都新建了一个内容为xyz的正则表达式对象。它们的主要区别是,第一种方法在引擎编译代码时,就会新建正则表达式,第二种方法在运行时新建正则表达式,所以前者的效率较高。而且,前者比较便利和直观,所以实际应用中,基本上都采用字面量定义正则表达式。
RegExp构造函数还可以接受第二个参数,表示修饰符。
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;
-
修饰符
- i: 不区分大小写匹配。例如,/hello/i 可以匹配 "hello"、"Hello"、"HELLO" 等。
- g: 全局匹配。如果正则表达式带有此修饰符,将会找到所有匹配项,而不是在找到第一个匹配项后停止。例如,/abc/g 可以匹配 "abcabcabc" 中的所有 "abc"。
- m: 多行匹配。启用这个修饰符后,^ 和 $ 将匹配字符串的每一行的开头和结尾,而不仅仅是整个字符串的开头和结尾。
- s: 单行匹配。启用这个修饰符后,. 将匹配包括换行符在内的任意字符。
- u: 启用 Unicode 匹配。用于处理 Unicode 字符串,允许匹配 Unicode 字符。
- y: 粘附匹配。它要求从目标字符串的特定位置开始匹配,从上一次匹配的结束位置继续。这在进行连续的匹配时很有用。
实列:
const text = "Hello, World! Hello, hello.";
const regex = /hello/gi; // 匹配所有的 "hello",不区分大小写
const matches = text.match(regex);
console.log(matches); // Output: [ 'Hello', 'hello', 'hello' ]:
1.实列属性
示列:
var r = /abc/igm;
r.ignoreCase // true
-
实例方法
- 示例
- RegExp.prototype.exec()
var s = '_x_x';
var r = /_(x)/;
r.exec(s) // ["_x", "x"]
如果正则表示式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的length属性等于组匹配的数量再加1。
上面代码的exec()方法,返回一个数组。第一个成员是整个匹配的结果,第二个成员是圆括号匹配的结果。
- String.prototype.match()
var s = 'abba';
var r = /a/g;
s.match(r) // ["a", "a"]
r.exec(s) // ["a"]
- String.prototype.search()
'_x_x'.search(/x/) // 1
上面代码中,第一个匹配结果出现在字符串的1号位置。
- String.prototype.replace()
'aaa'.replace('a', 'b') // "baa"
'aaa'.replace(/a/, 'b') // "baa"
'aaa'.replace(/a/g, 'b') // "bbb"
replace方法的第二个参数可以使用美元符号$,用来指代所替换的内容。更详细请自行搜索
- String.prototype.split()
- 正则分隔,去除多余的空格
'a, b,c, d'.split(/, */)
// [ 'a', 'b', 'c', 'd' ]
- 指定返回数组的最大成员
'a, b,c, d'.split(/, */, 2)
[ 'a', 'b' ]
-
匹配规则
字面量字符和元字符
- 点字符(.)
点字符(.)匹配除回车(\r)、换行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的任意一个字符。注意,对于码点大于0xFFFF字符,点字符不能正确匹配,会认为这是两个字符。
/c.t/
上面代码中,c.t匹配c和t之间包含任意一个字符的情况
- 位置字符
位置字符用来提示字符所处的位置,主要有两个字符。
- ^ 表示字符串的开始位置
- $ 表示字符串的结束位置
// test必须出现在开始位置
/^test/.test('test123') // true
// test必须出现在结束位置
/test$/.test('new test') // true
(3)选择符(|)
竖线符号(|)在正则表达式中表示“或关系”(OR),即cat|dog表示匹配cat或dog。
多个选择符可以联合使用。
// 匹配fred、barney、betty之中的一个
/fred|barney|betty/
选择符会包括它前后的多个字符,比如/ab|cd/指的是匹配ab或者cd,而不是指匹配b或者c。如果想修改这个行为,可以使用圆括号。
/a( |\t)b/.test('a\tb') // true
上面代码指的是,a和b之间有一个空格或者一个制表符。
其他的元字符还包括\、*、+、?、()、[]、{}等
转义符
正则表达式中那些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠。比如要匹配+,就要写成\+。
正则表达式中,需要反斜杠转义的,一共有12个字符:^、.、[、$、(、)、|、*、+、?、{和\。需要特别注意的是,如果使用RegExp方法生成正则对象,转义需要使用两个斜杠,因为字符串内部会先转义一次。
特殊字符
正则表达式对一些不能打印的特殊字符,提供了表达方法。
- \cX 表示Ctrl-[X],其中的X是A-Z之中任一个英文字母,用来匹配控制字符。
- [\b] 匹配退格键(U+0008),不要与\b混淆。
- \n 匹配换行键。
- \r 匹配回车键。
- \t 匹配制表符 tab(U+0009)。
- \v 匹配垂直制表符(U+000B)。
- \f 匹配换页符(U+000C)。
- \0 匹配null字符(U+0000)。
- \xhh 匹配一个以两位十六进制数(\x00-\xFF)表示的字符。
- \uhhhh 匹配一个以四位十六进制数(\u0000-\uFFFF)表示的 Unicode 字符。
字符类
字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内,比如[xyz] 表示x、y、z之中任选一个匹配。
/[abc]/.test('hello world') // false
/[abc]/.test('apple') // true
上面代码中,字符串hello world不包含a、b、c这三个字母中的任一个,所以返回false;字符串apple包含字母a,所以返回true。
有两个字符在字符类中有特殊含义。
- 脱字符(^)
如果方括号内的第一个字符是[^],则表示除了字符类之中的字符,其他字符都可以匹配。比如,[^xyz]表示除了x、y、z之外都可以匹配。
/[^abc]/.test('bbc news') // true
如果方括号内没有其他字符,即只有[^],就表示匹配一切字符,其中包括换行符。示例如下
var s = 'Please yes\nmake my day!';
s.match(/yes.*day/) // null
s.match(/yes[^]*day/) // [ 'yes\nmake my day']
注意,脱字符只有在字符类的第一个位置才有特殊含义,否则就是字面含义。
- 连字符(-)
某些情况下,表示字符的连续范围。比如,[abc]可以写成[a-c],[0123456789]可以写成[0-9],同理[A-Z]表示26个大写字母。
当连字号不出现在方括号之中,就不具备简写的作用,只代表字面的含义
以下都是合法的字符类简写形式。
[0-9.,]
[0-9a-fA-F]
[a-zA-Z0-9-]
[1-31]——>不代表1到31,只代表1到3。
连字符还可以用来指定 Unicode 字符的范围。
var str = "\u0130\u0131\u0132";
/[\u0128-\uFFFF]/.test(str)
// true
上面代码中,\u0128-\uFFFF表示匹配码点在0128到FFFF之间的所有字符。
预定义模式
预定义模式指的是某些常见模式的简写方式。
- \d 匹配0-9之间的任一数字,相当于[0-9]。
- \D 匹配所有0-9以外的字符,相当于[^0-9]。
- \w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]。
- \W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]。
- \s 匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]。
- \S 匹配非空格的字符,相当于[^ \t\r\n\v\f]。
- \b 匹配词的边界。
- \B 匹配非词边界,即在词的内部。
重复类——大括号({})
模式的精确匹配次数,使用大括号({})表示。{n}表示恰好重复n次,{n,}表示至少重复n次,{n,m}表示重复不少于n次,不多于m次。
/lo{2}k/.test('look') // true
/lo{2,5}k/.test('looook') // true
上面代码中,第一个模式指定o连续出现2次,第二个模式指定o连续出现2次到5次之间。
量词符——?、*、+
量词符用来设定某个模式出现的次数。
- ? 问号表示某个模式出现0次或1次,等同于{0, 1}。
- * 星号表示某个模式出现0次或多次,等同于{0,}。
- + 加号表示某个模式出现1次或多次,等同于{1,}。
贪婪模式——最大可能匹配
上一小节的三个量词符,默认情况下都是最大可能匹配,即匹配到下一个字符不满足匹配规则为止。这被称为贪婪模式。
var s = 'aaa';
s.match(/a+/) // ["aaa"]
非贪婪模式,即最小可能匹配。只要一发现匹配,就返回结果,不要往下检查。如果想将贪婪模式改为非贪婪模式,可以在量词符后面加一个问号。
var s = 'aaa';
s.match(/a+?/) // ["a"]
上面例子中,模式结尾添加了一个问号/a+?/,这时就改为非贪婪模式,一旦条件满足,就不再往下匹配,+?表示只要发现一个a,就不再往下匹配了。
- +?:表示某个模式出现1次或多次,匹配时采用非贪婪模式。
- *?:表示某个模式出现0次或多次,匹配时采用非贪婪模式。
- ??:表格某个模式出现0次或1次,匹配时采用非贪婪模式。
'abb'.match(/ab*/) // ["abb"]
'abb'.match(/ab*?/) // ["a"]
'abb'.match(/ab?/) // ["ab"]
'abb'.match(/ab??/) // ["a"]
上面例子中,/ab*/表示如果a后面有多个b,那么匹配尽可能多的b;/ab*?/表示匹配尽可能少的b,也就是0个b。
组匹配——’()’
- 概述
正则表达式的括号表示分组匹配,括号中的模式可以用来匹配分组的内容。
/fred+/.test('fredd') // true
/(fred)+/.test('fredfred') // true
上面代码中,第一个模式没有括号,结果+只表示重复字母d,第二个模式有括号,结果+就表示匹配fred这个词。
下面是另外一个分组捕获的例子。
var m = 'abcabc'.match(/(.)b(.)/);
m
// ['abc', 'a', 'c']
上面代码中,正则表达式/(.)b(.)/一共使用两个括号,第一个括号捕获a,第二个括号捕获c。
注意,使用组匹配时,不宜同时使用g修饰符,否则match方法不会捕获分组的内容。
- 非捕获组——(?:x)
(?:x)称为非捕获组(Non-capturing group),表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。
请看下面的例子。
var m = 'abc'.match(/(?:.)b(.)/);
m // ["abc", "c"]
上面代码中的模式,一共使用了两个括号。其中第一个括号是非捕获组,所以最后返回的结果中没有第一个括号,只有第二个括号匹配的内容。
下面是用来分解网址的正则表达式。
// 正常匹配
var url = /(http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/;
url.exec('http://google.com/');
// ["http://google.com/", "http", "google.com", "/"]
// 非捕获组匹配
var url = /(?:http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/;
url.exec('http://google.com/');
// ["http://google.com/", "google.com", "/"]
上面的代码中,前一个正则表达式是正常匹配,第一个括号返回网络协议;后一个正则表达式是非捕获匹配,返回结果中不包括网络协议。
- 先行断言——x(?=y)
x(?=y)称为先行断言(Positive look-ahead),x只有在y前面才匹配,y不会被计入返回结果。
比如,要匹配后面跟着百分号的数字,可以写成/\d+(?=%)/。
“先行断言”中,括号里的部分是不会返回的。
var m = 'abc'.match(/b(?=c)/);
m // ["b"]
上面的代码使用了先行断言,b在c前面所以被匹配,但是括号对应的c不会被返回。
- 先行否定断言——x(?!y)
x(?!y)称为先行否定断言(Negative look-ahead),x只有不在y前面才匹配,y不会被计入返回结果。
比如,要匹配后面跟的不是百分号的数字,就要写成/\d+(?!%)/。
/\d+(?!\.)/.exec('3.14')
// ["14"]
上面代码中,正则表达式指定,只有不在小数点前面的数字才会被匹配,因此返回的结果就是14。
“先行否定断言”中,括号里的部分是不会返回的。
var m = 'abd'.match(/b(?!c)/);
m // ['b']
上面的代码使用了先行否定断言,b不在c前面所以被匹配,而且括号对应的d不会被返回。
注意:利用正则表达式和编码方式可以实行多样操作
-
Javascript对象
概述
对象(object)是 JavaScript 语言的核心概念,也是最重要的数据类型。
什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
var obj = {
foo: 'Hello',};
上面代码中,大括号就定义了一个对象,它被赋值给变量obj,所以变量obj就指向一个对象。该对象内部包含两个键值对(又称为两个“成员”),第一个键值对是foo: 'Hello',其中foo是“键名”(成员的名称),字符串Hello是“键值”(成员的值)。
键名、属性、方法、创建
- 对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。
- 如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。
- 对象的每一个键名又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。
var obj = {
p: function (x) {
return 2 * x;
}
};
obj.p(1) // 2
如果属性的值还是一个对象,就形成了链式引用。
对象的属性之间用逗号分隔,最后一个属性后面可以加逗号,也可以不加。
- 属性可以动态创建,不必在对象声明时就指定。
var obj = {};
obj.foo = 123;
obj.foo // 123
上面代码中,直接对obj对象的foo属性赋值,结果就在运行时创建了foo属性。JavaScript 允许属性的“后绑定”,也就是说,你可以在任意时刻新增属性,没必要在定义对象的时候,就定义好属性。。
对象的引用
如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。如果取消某一个变量对于原对象的引用,不会影响到另一个变量。
这种引用只局限于对象,如果两个变量指向同一个原始类型的值。那么,变量这时都是值的拷贝。
var x = 1;
var y = x;
x = 2;
y // 1
上面的代码中,当x的值发生变化后,y的值并不变,这就表示y和x并不是指向同一个内存地址。
对象采用大括号表示,这导致了一个问题:如果行首是一个大括号,它到底是表达式还是语句?
{ foo: 123 }
JavaScript 引擎读到上面这行代码,会发现可能有两种含义。第一种可能是,这是一个表达式,表示一个包含foo属性的对象;第二种可能是,这是一个语句,表示一个代码区块,里面有一个标签foo,指向表达式123。
为了避免这种歧义,JavaScript 引擎的做法是,如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块。
{ console.log(123) } // 123
上面的语句是一个代码块,而且只有解释为代码块,才能执行。
如果要解释为对象,最好在大括号前加上圆括号。因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象。
这种差异在eval语句(作用是对字符串求值)中反映得最明显。
eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}
上面代码中,如果没有圆括号,eval将其理解为一个代码块;加上圆括号以后,就理解成一个对象。
属性的操作
属性的读取、赋值
- 读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。
var obj = { p: 'Hello World'};
obj.p // "Hello World"
obj['p'] // "Hello World"
上面代码分别采用点运算符和方括号运算符,读取属性p。
请注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。
var foo = 'bar';
var obj = {
foo: 1,
bar: 2
};
obj.foo // 1
obj[foo] // 2
上面代码中,引用对象obj的foo属性时,如果使用点运算符,foo就是字符串;如果使用方括号运算符,但是不使用引号,那么foo就是一个变量,指向字符串bar。
- 方括号运算符内部还可以使用表达式。
obj['hello' + ' world']
obj[3 + 3]
数字键可以不加引号,因为会自动转成字符串。
注意,数值键名不能使用点运算符(因为会被当成小数点),只能使用方括号运
- 点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
var obj = {};
obj.foo = 'Hello';
obj['bar'] = 'World';
属性的查看、删除
- 查看一个对象本身的所有属性,可以使用Object.keys方法。
var obj = {};
Object.keys(obj);
- delete命令用于删除对象的属性,删除成功后返回true。
var obj = { p: 1 };
Object.keys(obj) // ["p"]
delete obj.p // true
上面代码中,delete命令删除对象obj的p属性。
注意,删除一个不存在的属性,delete不报错,而且返回true。因此,不能根据delete命令的结果,认定某个属性是存在的。
另外,需要注意的是,delete命令只能删除对象本身的属性,无法删除继承的属性
var obj = {};
delete obj.toString // true
obj.toString // function toString() { [native code] }
上面代码中,toString是对象obj继承的属性,虽然delete命令返回true,但该属性并没有被删除,依然存在。这个例子还说明,即使delete返回true,该属性依然可能读取到值。
属性的遍历:for...in 循环
for...in循环用来遍历一个对象的全部属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log('键名:', i);
console.log('键值:', obj[i]);
}
for...in循环有两个使用注意点。
- 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
- 它不仅遍历对象自身的属性,还遍历继承的属性。
举例来说,对象都继承了toString属性,但是for...in循环不会遍历到这个属性。
对象obj继承了toString属性,该属性不会被for...in循环遍历到,因为它默认是“不可遍历”的。关于对象属性的可遍历性,参见《标准库》章节中 Object 一章的介绍。
如果继承的属性是可遍历的,那么就会被for...in循环遍历到。但是,一般情况下,都是只想遍历对象自身的属性,所以使用for...in的时候,应该结合使用hasOwnProperty方法,在循环内部判断一下,某个属性是否为对象自身的属性。
with语句的格式如下:
with (对象) {
语句;
}
它的作用是操作同一个对象的多个属性时,提供一些书写的方便。
with (document.links[0]){
console.log(href);
console.log(title);
console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);
注意,如果with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。
这是因为with区块没有改变作用域,它的内部依然是当前作用域。这造成了with语句的一个很大的弊病,就是绑定对象不明确。
with (obj) {
console.log(x);
}
建议不要使用with语句,可以考虑用一个临时变量代替with。
with(obj1.obj2.obj3) {
console.log(p1 + p2);
}
// 可以写成
var temp = obj1.obj2.obj3;
console.log(temp.p1 + temp.p2);