对象的扩展
属性的简洁表示法
- ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
- ES6允许在对象之中,只写属性名,不写属性值。这时,属性值等于属性名所代表的变量。除了属性简写,方法也可以简写。
- 用处:
- 用于函数的返回值,会非常方便。
- CommonJS模块输出变量,就非常合适使用简洁写法。
- 属性的赋值器(setter)和取值器(getter),也是采用这种写法。
- 注意:简洁写法的属性名总是字符串,这会导致一些看上去比较奇怪的结果。如果某个方法的值是一个Generator函数,前面需要加上星号。
属性名表达式
- 用表达式作为属性名,要将表达式放在方括号之内。例如:obj[‘a’+‘bc’]=123
- 如果使用字面量方式定义对象(使用大括号),在ES5中只能使用标识符定义属性。ES6允许字面量定义对象时,用方法二表达式作为对象的属性名,即把表达式放在方括号内。
- 表达式还可以用于定义方法名。
- 注意:属性名表达式与简洁表示法,不能同时使用,会报错。
方法的name属性
- 函数的 name属性,返回函数名。对象方法也是函数,因此也有 name 属性
- 方法的 name 属性返回函数名(即方法名)。如果使用了取值函数,则会在方法名前加上 get 。如果是存值函数,方法名的前面会加上 set 。
- 有两种特殊情况:bind 方法创造的函数,name 属性返回“bound”加上原函数的名字;Function 构造函数创造的函数,name 属性返回“anonymous”。
- 如果对象的方法是一个Symbol值,那么 name 属性返回的是这个Symbol值的描述
Object.is()
- Object.is() 用来比较两个值是否严格相等,他与严格比较运算符(===)的行为基本一致
- 不同之处有两个:
- Object.is()中,+0不等于-0, (===)中相等
- Object.is()中, NaN等于自身, (===)中不相等
Object.assign()
- Object.assign 方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两 个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出 TypeError错误。
- 注意:如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- Object.assign 只拷贝自身属性,不可枚举的属性(enumerable为false)和继承的属性不会被拷贝。例子如下,该对象只有一个不可枚举的属性invisible
Object.defineProperty({}, 'invisible', { enumerable:false, value:'hello' })
- 属性名为Symbol值的属性,也会被拷贝
- 对于嵌套对象,Object.assign的处理方法是替换,而不是添加,这点需要特别小心
- 注意:Object.assign可以用来处理数组,但是会把数组视为对象
- Object.assign的用法
- 为对象添加属性
- 为对象添加方法
- 克隆对象:采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采 用下面的代码。
function clone(origin){ let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
- 合并多个对象
- 为属性指定默认值
属性的可枚举性
- 对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnpropertyDescriptor 方法可以获取该属性的描述对象
- 描述对象的 enumerable属性,称为”可枚举性“,如果该属性为 false ,就表示某些操作会忽略当前属性。
- ES5有三个操作会忽略 enumerable 为 false 的属性。
- for…in 循环:只遍历对象自身的和继承的可枚举的属性
- Object.keys():返回对象自身的所有可枚举的属性的键名
- JSON.stringify():只串行化对象自身的可枚举的属性
- ES6新增了两个操作,会忽略enumerable 为 false 的属性。
- Object.assign():只拷贝对象自身的可枚举的属性
- Reflect.enumerate():返回所有 for…in 循环会遍历的属性
- 这五个操作之中,只有 for…in 和 Reflect.enumerate()会返回继承的属性
- 实际上,引入enumerable 的最初目的,就是让某些属性可以规避掉 for…in 操作。比如,对象原型的 toString方法,以及数组的 length 属
性,就通过这种手段,不会被 for…in 遍历到 - ES6规定,所有Class的原型的方法都是不可枚举的。
- 总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不 要用 for…in 循环,而用 Object.keys() 代替
属性的遍历
ES6一共有6种方法可以遍历对象的属性。
- for…in : 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
- Object.keys(obj):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
- Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
- Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有Symbol属性。
- Reflect.ownKeys(obj):返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举。
- Reflect.enumerate(obj):返回一个Iterator对象,遍历对象自身的和继承的所有可枚举属性(不含Symbol属性), 与 for…in 循环相同。
- 以上的6种方法遍历对象的属性,都遵守同样的属性遍历的次序规则。首先遍历所有属性名为数值的属性,按照数字排序。 其次遍历所有属性名为字符串的属性,按照生成时间排序。 后遍历所有属性名为Symbol值的属性,按照生成时间排序。
__proto__属性
- __proto__属性(前后各两个下划线)用来读取或设置当前对象的prototype对象
- 无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面的 Object.setPrototypeOf() (写 操作)、Object.getPrototypeOf(读操作)、Object.create(生成操作)代替。
- 在实现上,__proto__调用的是Object.prototype.proto
- 如果一个对象本身部署了__proto__ 属性,则该属性的值就是对象的原型。
Object.setPrototypeOf()
- 该方法的作用与__proto__相同,用拉力设置一个对象的prototype对象,它是ES6正式推荐的设置原型对象的方法
Object.getPrototypeOf()
该方法与setPrototypeOf方法配套,用于读取一个对象的prototype对象。
对象的扩展运算符
- Rest 参数
- Rest参数用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。 - 扩展运算符
- 扩展运算符用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。这等同于Object.assign方法
- 扩展运算符可以用于合并两个对象。
- 扩展运算符还可以用自定义属性,会在新对象之中,覆盖掉原有参数。
- 扩展运算符的参数对象之中,如果有取值函数 get ,这个函数是会执行的。
- 如果扩展运算符的参数是null或undefined,这个两个值会被忽略,不会报错。
Symbol
概述
- ES6引入Symbol的原因:保证每个属性的名字都是独一无二,这样就从根本上防止属性名的冲突。
- ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型
- Symbol值通过 Symbol 函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串, 另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
- 注意: Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对 象。也就是说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
- Symbol 函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为 字符串时,比较容易区分。
- 注意: Symbol 函数的参数只是表示对当前Symbol值的描述,因此相同参数的›„‘Ž 函数的返回值是不相等 的。
- Symbol值不能与其他类型的值进行运算,会报错。
- Symbol值可以显式转为字符串。
- Symbol值也可以转为布尔值,但是不能转为数值。
作为属性名的Symbol
- 由于每一个Symbol值都是不相等的,这意味着Symbol值可以作为标识符,用于对象的属性名,就能保证不会 出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
- Symbol值作为对象属性名时,不能用点运算符。
- 在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中
- Symbol类型还可以用于定义一组常量,保证这组常量的值都是不相等的。
- 常量使用Symbol值大的好处,就是其他任何值都不可能有相同的值了,因此可以保证上面的 switch 语句会 按设计的方式工作
- Symbol值作为属性名时,该属性还是公开属性,不是私有属性
属性名的遍历
- Symbol作为属性名,该属性不会出现在 for…in 、for…of 循环中,也不会被 Object.keys() 、Object.getOwnPropertyNames() 返回。但是,它也不是私有属性,有一 个Object.getOwnPropertySymbols 方法,可以获取指定对象的所有Symbol属性名。
- Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值。
- 使用Object.getOwnPropertyNames 方法得不到Symbol属性名,需要使用Object.getOwnPropertySymbols 方法
- Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和Symbol键名
Symbol.for(),Symbol.keyFor()
- 有时,我们希望重新使用同一个Symbol值,Symbol.for() 方法可以做到这一点。它接受一个字符串作为参数, 然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。
- Symbol.for() 与Symbol() 这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供 搜索,后者不会。Symbol.for() 不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是 否已经存在,如果不存在才会新建一个值
- Symbol.keyFor方法返回一个已登记的Symbol类型值的key
- Symbol.for() 为Symbol值登记的名字,是全局环境的,可以在不同的iframe或service worker中取到同一个值。
内置的Symbol值
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
- Symbol.hasInstance:对象的该属性指向一个内部方法。该对象使用 instanceof 运算符时,会调用这个方法, 判断该对象是否为某个构造函数的实例。
- Symbol.isConcatSpreadable:对象的该属性等于一个布尔值,表示该对象使用Array.prototype.concat()时,是否可以展开
- 数组该属性默认为true,表示可以展开
- 类似数组的对象也可以展开,但它的该属性默认为false,必须手动打开
- 对一个类来说,该属性必须写成一个返回布尔值的方法
- Symbol.species:对象的该属性,指向一个方法,该对象作为构造函数创造实例时,会调用这个方法,即如果 this.constructor[Symbol.species] 存在,就会使用这个属性作为构造函数,来创造新的实例对象
- Symbol.match:对象的该属性,指向一个函数,当执行str.match(myObject) 时,如果该属性存在,会调用它,返 回该方法的返回值。
- Symbol.replace:对象的该属性,指向一个方法,当该对象被String.prototype.replace 方法调用时,会返回该方法的返回值。
- Symbol.search:对象的该属性,指向一个方法,当该对象被String.prototype.search 方法调用时,会返回该方法的返回值。
- Symbol.split:对象的该属性,指向一个方法,当该对象被String.prototype.split 方法调用时,会返回该方法的返回值。
- Symbol.iterator:对象的Symbol.iterator属性,指向该对象的默认遍历器方法,即该对象进行for…of循环时,会调用这个方 法,返回该对象的默认遍历器
- Symbol.toPrimitive:对象的该属性,指向一个方法,该对象被转为原始类型的值时,会调用这个方法,返回该对 象对应的原始类型值。
- 该属性被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。
- Number:该场合需要转成数值
- String:该场合需要转成字符串
- Default:该场合可以转成数值,也可以转成字符串
- 该属性被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。
- Symbol.toStringTag:对象的该属性,指向一个方法。在该对象上面调用 Object.prototype.toString 方法时,如 果这个属性存在,它的返回值会出现在 toString 方法返回的字符串之中,表示对象的类型。也就是说,这个属 性可以用来定制 [object Object] 或 [object Array] 中object后面的那个字符串。
- Symbol.unscopables:对象的该属性,指向一个对象。该对象指定了使用 with 关键字时,哪些属性会被 with环境 排除。