es6-object

Posted by XuBaoshi on June 30, 2017

ECMAScript.6 对象相关

对象字面量

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

上述代码 createPerson函数返回一个属性名与当前函数参数名相同的对象,如果使用es6语法书写起来会更加简单。

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

简化对象方法

// es5
var person = {
    name:"Nicholas",
    sayName:function(){
        console.log(this.name);
    }
}

// es6
var person = {
    name:'Nicholas',
    sayName(){
        console.log(this.name);
    }
}

上述两种定义对象方法的区别是 第二种方法可以使用 super。

计算属性

es6之前我们可以在对象的实例上使用 ‘[]’的方式代替 ‘.’设置与获取属性,’[]’内允许使用变量 及进行一些相关的计算, 计算后的结果(String)作为对象的属性使用,但声明对象字面量时则无法使用’[]’,es6增加了对此功能的支持。

// es6前
var a = {};
var num = 1;
a['b' + num] = '2';
a['a b']= '3';
console.log(a.b1);
console.log(a['b' + num]);
console.log(a['a b']);

// throw error
var b = {
    ['a' + '2']:'3'
}
console.log(b.a2);

// es6
// 对象字面量[] 内 使用变量作为属性名
var lastName = 'last name';
let person = {
    'first name':'Nicholas',
    [lastName]:'Zakas'
}
console.log(person['first name']);  // 'Nicholas'
console.log(person['last name']);   // 'Zakas'
console.log(person[lastName]);   // 'Zakas'

// [] 内可以进行计算
var suffix = ' name';
var person = {
    ['first' +  suffix]  : 'Nicholas',
    ['last' + suffix] : 'Zakas'
}
console.log(person['first name']);  // 'Nicholas'
console.log(person['last name']);   // 'Zakas'

属性的遍历顺序

  1. for...in 只遍历对象自身和继承的可枚举属性(包含继承,不包含Symbol)。
  2. Object.keys(obj) 返回对象自身的所有可枚举属性的键名(不包含Symbol)
  3. Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性(但是包括不可枚举属性,不包含Symbol)。

以上方法返回的属性次序规则:

  1. 遍历所有属性名为数值的属性,按照数字排序
  2. 遍历所有属性名为字符串的属性,按照生成时间排序
  3. 遍历所有属性名为Symbol值的属性,按照生成时间排序(Symbol)
var obj = {
    a: 1,
    0: 1,
    d: 1,
    2: 1,
    b: 1,
    1: 1
};

console.log(Object.getOwnPropertyNames(obj).join(""));  // "012adb"

obj.c = 1;

console.log(Object.getOwnPropertyNames(obj).join(""));  // "012adbc"

Object.is()

Object.is() 与 === 很相似,不同之处在于 +0 与 -0 的比较 、两个NaN之间的比较。

    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

    console.log(5 == "5"); //true
    console.log(5 === "5"); // false
    console.log(Object.is(5,"5")); //false 

Object.assign()

将源对象( source1,source2 )的所有可枚举属性,复制到目标对象(target)

Object.assgin(target,source1,source2)

var receiver = {};
Object.assign(receiver,
    {type:'js',name:'file.js'},
    {type:'css'}
)
console.log(receiver.type); // "css"
console.log(receiver.name); // "name"

如果使用Object.assgin 复制带有访问器属性的对象时,复制后的属性不是访问器属性而是数据属性。ps:Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

var recevier = {},
    supplier = {
        get name(){
            return 'file.js'
        }
    };
var descriptor1 = Object.getOwnPropertyDescriptor(supplier,'name');
console.log(descriptor1.value); //undefined
console.log(descriptor1.get); // get function
Object.assign(recevier,supplier);
var descriptor2 = Object.getOwnPropertyDescriptor(recevier,'name');
console.log(descriptor2.value); //file.js
console.log(descriptor2.get); // undefined

Object.setPrototypeOf

Object.setPrototypeOf设置对象的原型。

let person = {
    getGreeting(){
        return "Hello";
    }
};
let dog = {
    getGreeting(){
        return "Woof";
    }
};

// prototype is person
let friend = Object.create(person);
console.log(friend.getGreeting()); // "Hello"
console.log(Object.getPrototypeOf(friend) === person); // true

// set prototype to dog
Object.setPrototypeOf(friend,dog);
console.log(friend.getGreeting()); // "dog"
console.log(Object.getPrototypeOf(friend) === dog); // true

上面代码通过setProtoType方法改变了friend的protoType。

super

super这个关键字,既可以当作函数使用,也可以当作对象使用,super作为函数调用时,代表父类的构造函数。ES6要求,子类的构造函数必须执行一次super函数,当super作为对象时,super指的是当前对象的原型对象。下面的例子中super当做对象来使用。

重构原型对象方法时,如果使用es5方式书写可能会有如下报错:

/**es5**/
let person = {
    name:'person',
    getGreeting() {
        return "Hello";
    }
};
// prototype is person
let friend = {
    name:'friend',
    getGreeting() {
        return Object.getPrototypeOf(this).getGreeting.call(this) + ", hi!";
    }
};
Object.setPrototypeOf(friend, person);

// prototype is friend
// 也可以修改成 
// let relative = {};
// Object.setPrototypeOf(relative, friend);

let relative = Object.create(friend);
console.log(friend.getGreeting()); // "Hello"
console.log(friend.getGreeting()); // "Hello hi!"
console.log(relative.getGreeting()); // error!

relative的prototype为friend,relative.getGreeting() 执行时 Object.getPrototypeOf(this)为friend,this为relative,调用时又将this指向了relative,造成了死循环,导致内存溢出。

使用super便不会产生此情况。

/**es6 super**/

let person = {
    name:'person',
    getGreeting() {
        return "Hello";
    }
};

let friend1 = {
    name:'friend',
    getGreeting:function() {
        return super.getGreeting() + ", hi!";
    }
};

// error in  friend1
Object.setPrototypeOf(friend1, person);
console.log(friend1.getGreeting()); // "error"


// prototype is person
let friend = {
    name:'friend',
    getGreeting() {
        return super.getGreeting() + ", hi!";
    }
};


Object.setPrototypeOf(friend, person);
let relative = Object.create(friend);
console.log(friend.getGreeting()); // "Hello"
console.log(friend.getGreeting()); // "Hello hi!"
console.log(relative.getGreeting()); // "Hello hi!"