1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

docs(regex): 增加后行断言的介绍

This commit is contained in:
ruanyf 2016-02-27 19:01:07 +08:00
parent 1e8b21e22d
commit 342fe1da61
3 changed files with 64 additions and 6 deletions

View File

@ -312,7 +312,7 @@ Object.defineProperty(Object, 'is', {
## Object.assign() ## Object.assign()
`Object.assign`方法用将源对象source的所有可枚举属性复制到目标对象target它至少需要两个对象作为参数第一个参数是目标对象后面的参数都是源对象。只要有一个参数不是对象就会抛出TypeError错误。 `Object.assign`方法用于对象的合并,将源对象source的所有可枚举属性复制到目标对象target
```javascript ```javascript
var target = { a: 1 }; var target = { a: 1 };
@ -324,6 +324,8 @@ Object.assign(target, source1, source2);
target // {a:1, b:2, c:3} target // {a:1, b:2, c:3}
``` ```
`Object.assign`方法至少需要两个对象作为参数第一个参数是目标对象后面的参数都是源对象。只要有一个参数不是对象就会抛出TypeError错误。
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
```javascript ```javascript
@ -357,7 +359,19 @@ Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' })
// { a: 'b', Symbol(c): 'd' } // { a: 'b', Symbol(c): 'd' }
``` ```
对于嵌套的对象,`Object.assign`的处理方法是替换,而不是添加。 `Object.assign`方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
```javascript
var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
```
上面代码中,源对象`obj1``a`属性的值是一个对象,`Object.assign`拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。
对于这种嵌套的对象,一旦遇到同名属性,`Object.assign`的处理方法是替换,而不是添加。
```javascript ```javascript
var target = { a: { b: 'c', d: 'e' } } var target = { a: { b: 'c', d: 'e' } }
@ -366,7 +380,9 @@ Object.assign(target, source)
// { a: { b: 'hello' } } // { a: { b: 'hello' } }
``` ```
上面代码中,`target`对象的`a`属性被`source`对象的`a`属性整个替换掉了,而不会得到`{ a: { b: 'hello', d: 'e' } }`的结果。这通常不是开发者想要的,需要特别小心。有一些函数库提供`Object.assign`的定制版本比如Lodash的`_.defaultsDeep`方法),可以解决深拷贝的问题。 上面代码中,`target`对象的`a`属性被`source`对象的`a`属性整个替换掉了,而不会得到`{ a: { b: 'hello', d: 'e' } }`的结果。这通常不是开发者想要的,需要特别小心。
有一些函数库提供`Object.assign`的定制版本比如Lodash的`_.defaultsDeep`方法),可以解决浅拷贝的问题,得到深拷贝的合并。
注意,`Object.assign`可以用来处理数组,但是会把数组视为对象。 注意,`Object.assign`可以用来处理数组,但是会把数组视为对象。

View File

@ -54,6 +54,7 @@
- Mathias Bynens, [Unicode-aware regular expressions in ES6](https://mathiasbynens.be/notes/es6-unicode-regex): 详细介绍正则表达式的u修饰符 - Mathias Bynens, [Unicode-aware regular expressions in ES6](https://mathiasbynens.be/notes/es6-unicode-regex): 详细介绍正则表达式的u修饰符
- Axel Rauschmayer, [New regular expression features in ECMAScript 6](http://www.2ality.com/2015/07/regexp-es6.html)ES6正则特性的详细介绍 - Axel Rauschmayer, [New regular expression features in ECMAScript 6](http://www.2ality.com/2015/07/regexp-es6.html)ES6正则特性的详细介绍
- Yang Guo, [RegExp lookbehind assertions](http://v8project.blogspot.jp/2016/02/regexp-lookbehind-assertions.html):介绍后行断言
## 数值 ## 数值

View File

@ -147,12 +147,12 @@ r1.exec(s) // ["aa"]
r2.exec(s) // null r2.exec(s) // null
``` ```
上面代码有两个正则表达式一个使用g修饰符另一个使用y修饰符。这两个正则表达式各执行了两次第一次执行的时候两者行为相同剩余字符串都是“_aa_a”。由于g修饰没有位置要求所以第二次执行会返回结果而y修饰符要求匹配必须从头部开始所以返回null。 上面代码有两个正则表达式,一个使用`g`修饰符,另一个使用`y`修饰符。这两个正则表达式各执行了两次,第一次执行的时候,两者行为相同,剩余字符串都是`_aa_a`。由于g修饰没有位置要求所以第二次执行会返回结果而y修饰符要求匹配必须从头部开始所以返回`null`
如果改一下正则表达式保证每次都能头部匹配y修饰符就会返回结果了。 如果改一下正则表达式,保证每次都能头部匹配,`y`修饰符就会返回结果了。
```javascript ```javascript
var s = "aaa_aa_a"; var s = 'aaa_aa_a';
var r = /a+_/y; var r = /a+_/y;
r.exec(s) // ["aaa_"] r.exec(s) // ["aaa_"]
@ -346,3 +346,44 @@ escape('hi. how are you?')
"hi\\. how are you\\?" "hi\\. how are you\\?"
``` ```
## 后行断言
JavaScript语言的正则表达式只支持先行断言lookahead和先行否定断言negative lookahead不支持后行断言lookbehind和后行否定断言negative lookbehind
目前有一个提案在ES7加入后行断言。V8引擎4.9版已经支持Chrome浏览器49版打开”experimental JavaScript features“开关地址栏键入`about:flags`),就可以使用这项功能。
”先行断言“指的是,`x`只有在`y`前面才匹配,必须写成`/x(?=y)/`。比如,只匹配百分号之前的数字,要写成`/\d+(?=%)/`。”先行否定断言“指的是,`x`只有不在`y`前面才匹配,必须写成`x(?!y)`。比如,只匹配不在百分号之前的数字,要写成`/\d+(?!%)/`
```javascript
/\d+(?=%)/.exec("100% of US presidents have been male") // ["100"]
/\d+(?!%)/.exec("thats all 44 of them") // ["44"]
```
上面两个字符串,如果互换正则表达式,就会匹配失败。另外,还可以看到,正则表达式的括号之中的部分,是不计入返回结果的。
”后行断言“正好与”先行断言“相反,`x`只有在`y`后面才匹配,必须写成`/(?<=y)x/`。比如,只匹配美元符号之后的数字,要写成`/(?<=\$)\d+/`。”后行否定断言“则与”先行否定断言“相反,`x`只有不在`y`后面才匹配,必须写成`/(?<!y)x/`。比如,只匹配不在美元符号后面的数字,要写成`/(?<!\$)\d+/`
```javascript
/(?<=\$)\d+/.exec("Benjamin Franklin is on the $100 bill") // ["100"]
/(?<!\$)\d+/.exec("its is worth about €90") // ["90"]
```
上面的例子中,正则表达式的括号之中的部分,也是不计入返回结果。
但是,如果括号之中还有括号,就会当作组匹配,返回匹配结果。
```javascript
/h(?=(\w)+)/.exec("hodor") // ["h", "r"]
/(?<=(\w)+)r/.exec("hodor") // ["r", "h"]
```
上面代码中,第一个正则表达式是”先行断言“,只匹配后面跟着一个多个任意字符(`\w`)的`h`,这时符合条件的右边最后一个字符,会被括号之中的那个括号捕获返回,上例是`r`。第二个正则表达式是”后行断言“,只匹配前面是一个或多个任意字符(`\w`)的`r`,这时符合条件的左边第一个字符,会被括号之中的那个括号捕获返回,上例是`h`
括号之中的那个括号捕获的部分,还可以用反斜杠引用。但是,”后行断言“的反斜杠引用,与通常的顺序相反,必须在对应的那个括号之前。
```javascript
/(?<=(o)d\1)r/.exec("hodor") // null
/(?<=\1d(o))r/.exec("hodor") // ["r", "o"]
```
上面代码中,如果反斜杠引用(`\1`)在括号的后面,就不会得到匹配结果,必须放在前面才可以。