《ES6标准入门》阅读笔记——-对象的扩展

写在前面

本系列为在我读完阮一峰老师的《ES6标准入门》第二版之后,所做的阅读笔记的整理。

许多初学ES6, 同时和我一样初次阅读阮老师的这本书的时候, 读第一遍会越发的困惑, 因为阮老师上面说的很多的定义,方法,之前都是没有见过的, 读到后面才发现, 哦~原来是这样.

有一句话叫做”大神的世界我们不懂”, 所以我在初读第一遍《ES6标准入门》这本书的时候,也是踩了不少坑,读书的时候查阅了不少的资料.

所以,在这一系列的笔记教程中,我会从一个初学者的角度,向您讲述ES6的相关知识,在后面介绍的知识我会尽量不提前用,即使提前使用,也会同时做好标注,避免了阅读时各种查阅资料的烦恼.

系列博客将采用一个一个的样例,来说明书中的精华部分(当然,这只是我认为的),同时引导新手,快速入门ES6,并逐步将其投入到生产实践中。

同时,在阅读前也提醒您, 为了系统连贯性的学习ES6的基础知识,建议您从我的博客第一章开始阅读,当然,如果您对对应的知识已经有所了解,那么可以跳转到任意章节阅读,每一篇博客名中均有介绍该博客中涉及到的ES6的内容.

阮一峰老师的这本书是开源的,在其官方博客就可以下载到,但是我强烈建议大家去购买一本书, 一是方便自己查阅ES6中新增的众多API, 二也是表达一下对大神的敬仰.

属性的简洁表示法

ES6允许写入变量和函数作为对象的属性和方法, 也就是说,在ES6中是允许在对象中只写属性名,不写属性值的

1
2
3
4
5
6
7
8
var foo = 'bar'
var baz = {foo}
console.log(baz) // {foo: "bar"}

function f(x, y) {
return {x,y}
}
console.log(f(1, 2)) // {x: 1, y: 2}

除了属性简写,方法也是可以简写的

1
2
3
4
5
var o = {
method() {
return 'Hello!'
}
}

等价于

1
2
3
4
5
var o = {
method: function() {
return 'Hello'
}
}

CommonJS的模块输出变量就非常适合使用简洁写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var ms = {}

function getItem(key) {
return key in ms ? ms[key] : null
}

function setItem(key, value) {
ms[key] = value
}

function clear() {
ms = {}
}

module.exports = {getItem, setItem, clear}

上面代码的最后一句就等价于

1
2
3
4
5
module.exports = {
getItem: getItem,
setItem: setItem,
clear: clear
}

属性名表达式

ES6同时开放了使用表达式放在方括号内,作为字面量的方式定义对象

1
2
3
4
var obj = {
[propkey]: true,
['a' + 'bc']: 123
}

方法的name属性

函数的name属性返回函数名,对象方法也是函数,因此也存在name属性

1
console.log((new Function()).name) //anonymous

关于方法的name属性,存在以下几个特点

正常的情况下,函数的函数体的name值返回函数的名称

当我们使用get或者set方法对函数进行描述的时候,会返回对应的前缀加上函数名

当我们使用bind方法创造的函数,函数会有一个bound来修饰

当使用构造函数来创造的函数中,name值固定为anonymous

如果对象的方法是一个symbol值, 那么那么属性返回的是这个symbol值的描述

1
2
3
4
5
6
7
8
const key1 = Symbol('description')
const key2 = Symbol()
let obj = {
[key1]() {},
[key2]() {}
}
console.log(obj[key1].name) // '[description]'
console.log(obj[key2].name) // ''

Object.is()

Object.is() 是ES6新定义的方法,用于确定传入的两个参数是否严格相等

但是, 与全等 === 符号唯一不同的地方是 +0不等于-0 NaN等于自身NaN

1
2
3
4
5
console.log(-0 === +0)  // true
console.log(NaN === NaN) // false

console.log(Object.is(-0, +0)) // false
console.log(Object.is(NaN, NaN)) // true

在ES5中可以部署对应的方法, 来模拟Object.is的效果

1
2
3
4
5
6
7
8
9
10
11
Object.defineProperty(Object, 'is', {
value: function(x, y) {
if (x === y) {
return x !== 0 || 1 / x === 1 / y
}
return x !== x && y !== y
},
configurable: true,
enumerable: false,
writable: true
})

Object.assign()

Object.assign() 方法将源对象的所有可枚举属性复制到目标对象

1
2
3
4
5
6
let target = {a: 1}
let source1 = {b: 2}
let source2 = {c: 3}

Object.assign(target, source1, source2)
console.log(target) // {a: 1, b: 2, c: 3}

同样的,Object.assign 方法可以用来复制数组,但是因为会将数组视为一个对象,所以后面数组的对应数组下标的值会覆盖之前的数组的下标的值

1
2
3
4
var a = [1, 2, 3]
var b = [4, 5]
Object.assign(a, b)
console.log(a) // [4,5,3]

使用Object.assign可以将原始对象赋值到一个空对象, 就得到了原始对象的克隆

1
2
3
function clone(origin) {
return Object.assign({}, origin)
}

通过将对象赋值到一个空对象的方式,获得了这个origin对象的克隆

不过,采用这种方法克隆,只能克隆原始对象自身的值,而不能克隆它继承的值

那么,如果想要获得保持原型链的对象,那么就需要使用这样的方法

1
2
3
4
function clone(origin) {
let originProto = Object.getPrototypeOf(origin)
return Object.assign(Object.create(originProto), origin)
}

实现方式就是这样的,使用getPropertyOf方法获取了origin的原型,然后将函数体合并到原型中,并返回

当使用Object.assign() 对两个对象进行合并的时候,不论前面对应对象名称的内容是什么,其内容都会被替换掉

1
2
3
4
5
6
7
8
9
var target = {
a: {b: 'c',d: 'e'}
}
var source = {
a: {b: 'hello'}
}

Object.assign(target, source)
console.log(target) // a:{b: "hello"}

属性的可枚举性

ES6规定,所有class的原型的方法都是不可枚举的

1
2
3
4
5
6
var a = Object.getOwnPropertyDescriptor(
class {
foo() {}
}.prototype, 'foo'
).enumerable
console.log(a) // false

proto属性

proto属性用来读取或设置当前对象的prototype对象, 这个属性其实在很早版本的chrome Firefox Opera等现代浏览器中都已经得到了支持,被广泛用于查找原型上的方法和属性.

但是IE迟迟得不到支持,在ES6中,此属性被写到了规范中

让人欣喜的是,IE11开始,也支持此属性了

对应的, ES6也同时推出了Object.setPrototypeOf()方法, 该方法的作用与proto是相同的,只不过proto是一个内部方法, 因此TC39推荐使用Object.setPrototypeOf()来设置原型对象的方法.

对象的扩展运算符

ES7有个提案, 将rest参数,也就是扩展运算符引入对象,目前babel已经支持

rest参数(扩展运算符) 用于从一个对象取值,相当于将所有可遍历但尚未被读取的键但尚未读取的属性,分配到指定的对象上,所有的键及相应的值都会被赋值到新对象上

1
2
3
4
5
6
7
8
9
let {x, y, ...z} = {
x: 1,
a: 3,
y: 2,
b: 4,
}
console.log(x) // 1
console.log(y) // 2
console.log(z) // {a: 3, b: 4}

目前在Chrome中测试, 尚未支持上面的方法

有一点要注意的是,rest参数的复制是浅复制

1
2
3
4
let obj = {a: {b: 1}}
let {...x} = obj
obj.a.b = 2
console.log(x.a.b) // 2
文章目录
  1. 1. 写在前面
  2. 2. 属性的简洁表示法
  3. 3. 属性名表达式
  4. 4. 方法的name属性
  5. 5. Object.is()
  6. 6. Object.assign()
  7. 7. 属性的可枚举性
  8. 8. proto属性
  9. 9. 对象的扩展运算符
|