ES6 对象的新功能与解构赋值介绍
es6 通过字面量语法扩展、新增方法、改进原型等多种方式加强对象的使用,并通过解构简化对象的数据提取过程。
一、字面量语法扩展
在 es6 模式下使用字面量创建对象更加简洁,对于对象属性来说,属性初始值可以简写,并可以使用可计算的属性名称。对象方法的定义消除了冒号和 function 关键字,示例如下:
// demo1 var value = "name", age = 18 var person = { age, // age: age ['my' + value]: 'jenny', // myname sayname () { // sayname: function() console.log(this.myname) } } console.log(person.age) // 18 console.log(person.myname) // jenny person.sayname(); // jenny
针对重复定义的对象字面量属性,es5严格模式下会进行重复属性检查从而抛出错误,而es6移除了这个机制,无论严格模式还是非严格模式,同名属性都会取最后一个值。
// demo2 var person = { ['my' + value]: 'jenny', myname: 'tom', myname: 'lee', } console.log(person.myname) // lee
二、新增方法
从 es5 开始遵循的一个设计目标是,避免创建新的全局函数,也不在object.prototype上创建新的方法。
为了是某些任务更容易实现,es6 在全局 object 对象上引入一些新的方法。
2.1 object.is( )
es6 引入object.is()方法来弥补全等运算符的不准确计算。
全等运算符在比较时不会触发强制转换类型,object.is()运行结果也类似,但对于 +0 和 -0(在 js 引擎中为两个不同实体)以及特殊值nan的比较结果不同,示例来看:
// demo3 console.log(5 == '5') // true console.log(5 === '5') // false console.log(object.is(5, '5')) // false console.log(+0 == -0) // true console.log(+0 === -0) // true console.log(object.is(+0, -0)) // false console.log(nan == nan) // false console.log(nan === nan) // false console.log(object.is(nan, nan)) // true
总结来说,object.is()对所有值进行了更严格等价判断。当然,是否使用object.is()代替全等操作符(===)取决于这些特殊情况是否影响代码。
2.2 object.assign( )
es6 添加object.assign()来实现混合(mixin)模式,即一个对象接收另一个对象的属性和方法。注意是接收而不是继承,例如接收 demo1 中的对象:
// demo4 var friend = {} object.assign(friend, person) friend.sayname() // jenny console.log(friend.age) // 18 console.log(object.getprototypeof(friend) === person) // false
在object.assign()之前,许多 js 库自定义了混合方法 mixin( ) 来实现对象组合,代码类似于:
function mixin(receiver, supplier) { object.keys(supplier).foreach(function (key) { receiver[key] = supplier[key] }) return receiver }
可以看出 mixin( ) 方法使用“=”赋值操作,并不能复制访问器属性,同理object.assign()也不能复制访问器属性,只是执行了赋值操作,访问器属性最终会转变为接收对象的数据属性。示例如下:
// demo5 var animal = { name: 'lili', get type () { return this.name + type }, set type (news) { type = news } } animal.type = 'cat' console.log(animal.type) // lilicat var pet = {} object.assign(pet, animal) console.log(animal) // { name: 'lili', type: [getter/setter] } console.log(pet) // { name: 'lili', type: 'lilicat' }
2.3 object.setprototypeof( )
正常情况下对通过构造函数或object.create()创建时,原型是被指定的。es6 添加object.setprototypeof() 方法来改变对象的原型。
例如创建一个继承 person 对象的 coder 对象,然后改变 coder 对象的原型:
// demo6 let person = { myname: 'jenny', sayname () { console.log(this.myname) } } // 创建原型为 person 的 coder 对象 let coder = object.create(person) coder.sayname() // jenny console.log(object.getprototypeof(coder) === person) // true let hero = { myname: 'lee', sayname () { console.log(this.myname) } } // 改变 coder 对象的原型为 hero object.setprototypeof(coder, hero) coder.sayname() // lee console.log(object.getprototypeof(coder) === hero) // true
对象原型被存储在内部专有属性[[prototype]],调用object.getprototypeof()返回存储在其中的值,调用object.setprototypeof()改变其值。这个方法加强了对对象原型的操作,下一节重点讲解其它操作原型的方式。
三、增强对象原型
原型是 js 继承的基础,es6 针对原型做了很多改进,目的是更灵活地方式使用原型。除了新增的object.setprototypeof()改变原型外,还引入super关键字简化对原型的访问,
3.1 super关键字
es6 引入super来更便捷的访问对象原型,上一节介绍 es5 可以使用object.getprototypeof()返回对象原型。举例说明super的便捷,当对象需要复用原型方法,重新定义自己的方法时,两种实现方式如下:
// demo7 let coder1 = { getname () { console.log("coder1 name: ") object.getprototypeof(this).sayname.call(this) } } // 设置 coder1 对象的原型为 hero(demo6) object.setprototypeof(coder1, hero) coder1.getname() // coder1 name: lee let coder2 = { getname () { console.log("coder2 name: ") super.sayname() } } object.setprototypeof(coder2, hero) coder2.getname() // coder2 name: lee
在 coder1 对象的 getname 方法还需要call(this)保证使用的是原型方法的 this,比较复杂,并且在多重继承会出现递归调用栈溢出错误,而直接使用super就很简单安全。
注意必须在简写方法中使用super,要不然会报错,例如以下代码运行语法错误:
let coder4= { getname: function () { // getname () 正确 super.sayname() // syntaxerror: 'super' keyword unexpected here }
因为在例子中 getname 成为了匿名 function 定义的属性,在当前上下问调用super引用是非法的。如果不理解,可以进一步看下方法的从属对象。
3.2 方法的从属对象
es6 之前“方法”是具有功能而非数据的对象属性,es6 正式将方法定义为有 [[homeobject]]内部属性的函数。
[[homeobject]]属性存储当前方法的从属对象,例如:
let coder5 = { sayname () { console.log("i have homeobject") } } function sharename () { console.log("no homeobject") }
coder5 对象的 sayname( ) 方法的[[homeobject]]属性值为 coder5,而 function 定义的 sharename( ) 没有将其赋值给对象,所以没有定义其[[homeobject]]属性,这在使用super时很重要。
super就是在[[homeobject]]属性上调用object.getprototypeof()获得原型的引用,然后搜索原型得到同名函数,最后设置 this 绑定调用相应方法。
四、解构赋值
es6 为数组和对象字面量提供了新特性——解构,可以简化数据提取的过程,减少同质化的代码。解构的基本语法示例如下:
let user = { name: 'jenny', id: 18 } let {name, id} = user console.log(name, id) // jenny 18
注意在这段代码中,user.name 存储在与对象属性名同名的 name 变量中。
4.1 默认值
如果解构时变量名称与对象属性名不同,即在对象中不存在,那么这个变量会默认为undefined:
let user = { name: 'jenny', id: 18 } let {name, id, job} = user console.log(name, id, job) // jenny 18 undefined
4.2 非同名变量赋值
非同名变量的默认值为undefined,但更多时候是需要为其赋值的,并且会将对象属性值赋值给非同名变量。es6 为此提供了扩展语法,与对象字面量属性初始化程序很像:
let user = { name: 'jenny', id: 18 } let {name, id = 16, job = 'engineer'} = user console.log(name, id, job) // jenny 18 engineer let {name: localname, id: localid} = user console.log(localname, localid) // jenny 18 let {name: othername = 'lee', job: otherjob = 'teacher'} = user console.log(othername, otherjob) // jenny teacher
可以看出这种语法实际与对象字面量相反,赋值名在冒号左,变量名在右,并且解构赋值时,只是更新了默认值,不能覆盖对象原有的属性值。
4.3 嵌套解构
解构嵌套对象的语法仍然类似对象字面量,使用花括号继续查找下层结构:
let user = { name: 'jenny', id: 18, desc: { pos: { lng: 111, lat: 333 } } } let {desc: {pos}} = user console.log(pos) // { lng: 111, lat: 333 } let {desc: {pos: {lng}}} = user console.log(lng) // 111 let {desc: {pos: {lng: longitude}}} = user console.log(longitude) // 111
五、对象类别
es6 规范定义了对象的类别,特别是针对浏览器这样的执行环境。
- 普通(ordinary)对象
具有 js 对象所有的默认内部行为
- 特异(exotic)对象
具有某些与默认行为不符的内部行为
- 标准(standard)对象
es6 规范中定义的对象
可以是普通对象或特异对象,例如 date、array 等
- 内建对象
脚本开始执行时存在于 js 执行环境中的对象
所有标准对象都是内建对象
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。