五分钟学会ES6扩展对象的功能性

855 阅读6分钟

对象是javascript的核心,ES6中为对象提供了好多简单易用且更加灵活的新特性,如果熟练使用这些方法,能提高不少工作效率,下面一起来看一看:

一.对象字面量的语法扩展

属性初始值的简写

在ES5以及其之前的版本中,对象字面量只是键值对的集合,这意味着键和值会有重复的写法,例如下面:

function createObj(name,age){
    return {
        name:name,
	        age:age
    }
}

这样的写法相比我们每个人写了不下于100遍了,每次键值对都重复但是我们还只能忍受这种写法,好在ES6进行了改良,简直就是解放啊,来看看ES6是怎么写的

function createObj(name,age){
    return {
        name,
        age
    }
}

很清爽有没有,这两种写法达到的效果一样,简单解释一下ES6的这种写法,当对象字面量只有一个属性的名称时,javascript会在可访问的作用域中查找同名的变量,如果找到,则该变量的值赋值给对象字面量的同名属性。

对象方法的简写

方法的简写也是一样的,就是取消方法和function关键字,先来对比一下:

//ES5
var person ={
    name:'xiaomage',
    sayName:function(){
		console.log(this.name)
    }
}
let person = {
	name:'xiaomage',
    sayName(){
		console.log(this.name)
    }
}

达到的效果是一样的,唯一的区别就是简写方法可以使用Super关键字,后面的内容会一起讲到。

可计算属性名

我觉得这个真的是对象中改动比较好的一个,因为真的用起来很舒服,在以前的版本中,想要通过计算得到属性名,就需要在方括号中代替点记法,但是某些包含字符的字符串字面量会报错,其和变量放在方括号中是被允许的,看看下面的例子:

var person = {};
lastname = "last name";

person["first name"] = "xiaoma";
person[lastname] = "xiaomage";

console.log(person["first name"]); //xiaoma
console.log(person[lastname]);  // xiaomage

首先lastname被赋值为"last name",因为字符串之间含有空格,所以不能使用点标记法,但是可以使用中括号法,因为他支持任何形式的字符串作为名称访问属性的值。

此外,还有下面的写法,可以直接使用字符串字面量作为对象字面的属性名:

var person = {
    "first name":"xiaoma"
};

console.log(person["first name"])  // xiaoma

这种模式适用于提前知道名称,或者可被字符串字面量表示的情况。如果想上面的例子中的一样,属性值是变量的时候是无法做到的,但是在ES6中的可以使用中括号做到:

let fullname = 'last name';
let person1 = {
  firstname: 'xiaoma',
  [fullname]: 'xiaomage',
};
console.log (person1['firstname']); //xiaoma
console.log (person1[fullname]); //xiaomage
console.log (person1['last name']); //xiaomage

还有下面的感觉更自如了呢,想怎么用就怎么用有没有:

let suffix = " name";
let obj = {
    ["first" + suffix]:"xiaoma",
    ["full" + suffix]:"xiamage",
}
console.log(obj["first name"])  // xiaoma
console.log(obj["full name"])   //xiaomage

二. 新增方法

ECMAScript组织的目标是不再创建新的全局函数,也不在Object.prototype上面创建新的方法,,所以在全局的Objcet方法上面引入一些新的方法,供适当的时候使用。

Object.is()

Object.is()的出现可以说是弥补了全等(===)的不准确性,此方法接收两个参数,分别是要比较的值,如果这两个参数的值类型和值都相同的话,那么返回true,否则返回false。

Object.assign()

现在流行混合,ES6当然ES6也不例外,使用Object.assign()就可以实现,第一个参数 目标对象,其余的参数都是原对象,注意,如果源对象中有相同的属性名的属性的时候,会按照添加顺序,后面的值覆盖前面的值,所以这方法的典型场景就是对象的值改变的时候而不用单独去给某个属性赋值了,直接把对象付给前者,会把所有相同属性名值全部替换成新的,很方便,还有就是这事浅拷贝,知识复制对象的引用,也就是说一个改变不会影响另外一个。

三.重复的对象字面量属性

在ES5或者之前的版本中,严格模式下,如果对象的属性名有重复的话会报错,但是在ES6中,不管一般模式还是严格模式,都不会报错,而且相同的属性名,后者的值会覆盖前者的值。

//es5
"use strict"
var person = {
    name:'xiaoma',
    name:'xiaomage'  //语法错误
}
//es6
var person1 = {
    name:'xiaoma',
    name:'xiaoma_ge'
}
console.log(person1.name)  //xiaoma_ge

四.自有枚举属性顺序

es6之前是对对象的属性没有定义枚举的顺序的,在es6中就定义枚举的顺序规则:

  1. 所有的数字按升序排列,数字在字符串的前面。
  2. 所有的字符串键按照他们被加入时的顺序排列
  3. 所有的symbol键按照他们被加入对象时的顺序排列
var obj = {
	a:1,
    0:1,
    c:1,
    2:1,
    b:1,
    1:1
}
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join("")) // "012acbd"

对于for-in 循环,由于并非所有的厂商都遵循相同的实现方式,因此,仍未指定一个明确的枚举顺序,而,Onjects.keys()方法和JSON.stringify()都知明与for-in 使用相同的枚举顺序,因此,枚举顺序也不明确。

五.增强对象原型

改变对象的原型

在ES6之前的时候,不管是使用Object.create()创建对象还是使用构造函数创建对象,一旦对象创建完毕就不能更改其原型,只能通过Object.getPrototypeOf()来获取,但是在ES6中新增了Object.setPrototypeOf()来改变指定对象的原型,接收两个参数,被改变对象的原型和替代第一个参数原型的对象。

对象原型的真实值被储存在内部专有属性[[Prototype]]中,调用Object.getPrototype返回储存在其中的值,调用Object.setPrototype()方法改变其中的值。但是这不止操作[[Prototype]]的唯一的方法。

简化原型访问的Super引用

在ES6中引用了super特性,他可以更方便的访问对象属性,比如我们想要重写对象实例的方法,又想调用与他重名的原型方法,es5和es6的实现就大不相同:

六.正式的方法定义

在之前,方法仅仅是一个具有一个功能而非数据的对象属性,但在es6中正式定义了方法,他会有一个内部的[[HomeObject]]属性来容纳这个方法从属的对象。请思考以下代码:

let person = {
    //是方法
    getGreeting(){
        return "hello";
    }
}

//不是方法
function shareGreeting(){
    return "hi!"
}

这个示例中定义了person对象,他有一个getGreeting()方法,由于直接把函数赋值给person对象,因此getGreeting()方法的[[HomeObject]]属性值为person.而创建shareGreeting()函数时,由于未将其赋值给一个对象,因而没有[[HomeObject]]属性。

super的所有引用都通过[[HomeObject]]属性来确定后续的运行过程。第一步是在[[HomeObject]]属性上调用Object.getPrototypeOf()方法来检索原型的引用,然后搜索原型找到同名函数,最后,设置this绑定并且调用响应的方法。请看下面的示例:

let person = {
  getGreeting () {
    return 'hello';
  },
};

let friend = {
  getGreeting () {
    return super.getGreeting () + ',world';
  },
};

//将person设置为原型
Object.setPrototypeOf (friend, person);
console.log (friend.getGreeting ()); //hello,world
console.log (Object.getPrototypeOf (friend) === person); //true

调用friend.getGreeting()方法会将person.getGreeting()的返回值拼接成新的字符串并返回。friend.getGreeting()的[[HomeObject]]属性为friend,friend的原型是person,所以super().getGreeting()等价于person.getGreeting.call(this)。