diff --git a/docs/object.md b/docs/object.md index 3081815..22476e0 100644 --- a/docs/object.md +++ b/docs/object.md @@ -312,7 +312,7 @@ Object.defineProperty(Object, 'is', { ## Object.assign() -`Object.assign`方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。 +`Object.assign`方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。 ```javascript var target = { a: 1 }; @@ -324,6 +324,8 @@ Object.assign(target, source1, source2); target // {a:1, b:2, c:3} ``` +`Object.assign`方法至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。 + 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。 ```javascript @@ -357,7 +359,19 @@ Object.assign({ 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 var target = { a: { b: 'c', d: 'e' } } @@ -366,7 +380,9 @@ Object.assign(target, source) // { 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`可以用来处理数组,但是会把数组视为对象。 diff --git a/docs/reference.md b/docs/reference.md index 51422e2..2e8150b 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -54,6 +54,7 @@ - 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正则特性的详细介绍 +- Yang Guo, [RegExp lookbehind assertions](http://v8project.blogspot.jp/2016/02/regexp-lookbehind-assertions.html):介绍后行断言 ## 数值 diff --git a/docs/regex.md b/docs/regex.md index c1886f9..28beaa1 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -147,12 +147,12 @@ r1.exec(s) // ["aa"] r2.exec(s) // null ``` -上面代码有两个正则表达式,一个使用g修饰符,另一个使用y修饰符。这两个正则表达式各执行了两次,第一次执行的时候,两者行为相同,剩余字符串都是“_aa_a”。由于g修饰没有位置要求,所以第二次执行会返回结果,而y修饰符要求匹配必须从头部开始,所以返回null。 +上面代码有两个正则表达式,一个使用`g`修饰符,另一个使用`y`修饰符。这两个正则表达式各执行了两次,第一次执行的时候,两者行为相同,剩余字符串都是`_aa_a`。由于g修饰没有位置要求,所以第二次执行会返回结果,而y修饰符要求匹配必须从头部开始,所以返回`null`。 -如果改一下正则表达式,保证每次都能头部匹配,y修饰符就会返回结果了。 +如果改一下正则表达式,保证每次都能头部匹配,`y`修饰符就会返回结果了。 ```javascript -var s = "aaa_aa_a"; +var s = 'aaa_aa_a'; var r = /a+_/y; r.exec(s) // ["aaa_"] @@ -346,3 +346,44 @@ escape('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("that’s all 44 of them") // ["44"] +``` + +上面两个字符串,如果互换正则表达式,就会匹配失败。另外,还可以看到,正则表达式的括号之中的部分,是不计入返回结果的。 + +”后行断言“正好与”先行断言“相反,`x`只有在`y`后面才匹配,必须写成`/(?<=y)x/`。比如,只匹配美元符号之后的数字,要写成`/(?<=\$)\d+/`。”后行否定断言“则与”先行否定断言“相反,`x`只有不在`y`后面才匹配,必须写成`/(?