diff --git a/docs/class.md b/docs/class.md index 53671e6..9e021e0 100644 --- a/docs/class.md +++ b/docs/class.md @@ -111,7 +111,7 @@ prototype对象的constructor属性,直接指向“类”的本身,这与ES5 Point.prototype.constructor === Point // true ``` -另外,类的内部所有定义的方法,都是不可枚举的(enumerable)。 +另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。 ```javascript class Point { @@ -130,7 +130,7 @@ Object.getOwnPropertyNames(Point.prototype) // ["constructor","toString"] ``` -上面代码中,toString方法是Point类内部定义的方法,它是不可枚举的。这一点与ES5的行为不一致。 +上面代码中,`toString`方法是`Point`类内部定义的方法,它是不可枚举的。这一点与ES5的行为不一致。 ```javascript var Point = function (x, y){ diff --git a/docs/generator.md b/docs/generator.md index 665ba8a..c315a7c 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -644,13 +644,13 @@ function* gen() { var g = gen(); g.next() // { value: 1, done: false } -g.return("foo") // { value: "foo", done: true } +g.return('foo') // { value: "foo", done: true } g.next() // { value: undefined, done: true } ``` 上面代码中,遍历器对象`g`调用`return`方法后,返回值的`value`属性就是`return`方法的参数`foo`。并且,Generator函数的遍历就终止了,返回值的`done`属性为`true`,以后再调用`next`方法,`done`属性总是返回`true`。 -如果`return`方法调用时,不提供参数,则返回值的`vaule`属性为`undefined`。 +如果`return`方法调用时,不提供参数,则返回值的`value`属性为`undefined`。 ```javascript function* gen() { diff --git a/docs/object.md b/docs/object.md index 3e948c0..48ede3f 100644 --- a/docs/object.md +++ b/docs/object.md @@ -312,6 +312,8 @@ Object.defineProperty(Object, 'is', { ## Object.assign() +### 基本用法 + `Object.assign`方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。 ```javascript @@ -324,7 +326,7 @@ Object.assign(target, source1, source2); target // {a:1, b:2, c:3} ``` -`Object.assign`方法至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。 +`Object.assign`方法的第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。 @@ -338,7 +340,56 @@ Object.assign(target, source1, source2); target // {a:1, b:2, c:3} ``` -`Object.assign`只拷贝自身属性,不可枚举的属性(`enumerable`为false)和继承的属性不会被拷贝。 +如果只有一个参数,`Object.assign`会直接返回该参数。 + +```javascript +var obj = {a: 1}; +Object.assign(obj) === obj // true +``` + +如果该参数不是对象,则会先转成对象,然后返回。 + +```javascript +typeof Object.assign(2) // "object" +``` + +由于`undefined`和`null`无法转成对象,所以如果它们作为参数,就会报错。 + +```javascript +Object.assign(undefined) // 报错 +Object.assign(null) // 报错 +``` + +如果非对象参数出现在源对象的位置(即非首参数),那么处理规则有所不同。首先,这些参数都会转成对象,如果无法转成对象,就会跳过。这意味着,如果`undefined`和`null`不在首参数,就不会报错。 + +```javascript +let obj = {a: 1}; +Object.assign(obj, undefined) === obj // true +Object.assign(obj, null) === obj // true +``` + +其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。 + +```javascript +var v1 = 'abc'; +var v2 = true; +var v3 = 10; + +var obj = Object.assign({}, v1, v2, v3); +console.log(obj); // { "0": "a", "1": "b", "2": "c" } +``` + +上面代码中,`v1`、`v2`、`v3`分别是字符串、布尔值和数值,结果只有字符串合入目标对象(以字符数组的形式),数值和布尔值都会被忽略。这是因为只有字符串的包装对象,会产生可枚举属性。 + +```javascript +Object(true) // {[[PrimitiveValue]]: true} +Object(10) // {[[PrimitiveValue]]: 10} +Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"} +``` + +上面代码中,布尔值、数值、字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性`[[PrimitiveValue]]`上面,这个属性是不会被`Object.assign`拷贝的。只有字符串的包装对象,会产生可枚举的实义属性,那些属性则会被拷贝。 + +`Object.assign`拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(`enumerable: false`)。 ```javascript Object.assign({b: 'c'}, @@ -359,6 +410,8 @@ Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' }) // { a: 'b', Symbol(c): 'd' } ``` +### 注意点 + `Object.assign`方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。 ```javascript @@ -393,6 +446,8 @@ Object.assign([1, 2, 3], [4, 5]) 上面代码中,`Object.assign`把数组视为属性名为0、1、2的对象,因此目标数组的0号属性`4`覆盖了原数组的0号属性`1`。 +### 常见用途 + `Object.assign`方法有很多用处。 **(1)为对象添加属性** @@ -405,11 +460,11 @@ class Point { } ``` -上面方法通过assign方法,将x属性和y属性添加到Point类的对象实例。 +上面方法通过`Object.assign`方法,将`x`属性和`y`属性添加到`Point`类的对象实例。 **(2)为对象添加方法** -```javascript +```javascript Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ···