es6学习笔记之对象的扩展

2017-09-25  本文已影响0人  markpapa

一. 属性的简洁表示法

ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

var foo = 'bar' ; 
var baz = {foo};
baz // {foo : 'bar'}

//等同于
var baz = {foo : foo}

function f(x, y){
    return {x, y}
}

//等同于
function f(x, y){
    return { x : x, y : y};
}

f(1, 2) // object { x : 1, y : 2}

//方法也可以简写
var o = {
    method(){
          return "hello!" ; 
     }
  };

  //等同于
  var o = {
     method : function(){
            return "hello!" ;
          }
      };

var birth = '2000/01/01';
var person {
      name : '张三',
      //等同于birth : birth
      birth,
      //等同于hello : functon()....
      hello() {console.log(this.name)}
}

这种写法用于函数的返回值,将会非常方便。

function getPoint() {
    var x = 1;
    var y =10;
    return {x, y};
}

getPoint()
// { x : 1, y : 10}

二. 属性名表达式

obj . foo = true;
obj['a' + 'bc'] = 123;

如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一(标识符)定义属性。

var obj = {
    foo : true,
    abc : 123
 };

ES6 允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内。

let propKey = 'foo';
let obj = { 
      [propKey] : true,
      ['a' + 'bc'] : 123
 };

var lastWord = 'last word';
var a = {
    'first word' : 'hello',
     [lastWord] : 'world'
  };
  a['first word'] // 'hello'
  a[lastWord] // 'world'
  a['last word'] // 'world'

表达式还可以用于定义方法名。

let obj = {
   ['h' + 'ello'](){
        return 'hi';
   }
};

obj.hello() // hi

属性名表达式与简洁表示法,不能同时使用,会报错。

//报错
var foo = 'bar';
var bar = 'abc';
var baz = { [foo] };

//正确
var foo = 'bar';
var baz  = {[foo] : 'abc'}

属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object],这一点要特别小心。

const keyA = { a : 1};
const keyB = { b : 2};

const myObject ={
    [KeyA] : 'valueA',
    [KeyB] : 'valueB'
};

三. Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

var target = { a : 1 };
var source1 = { b : 2 };
var source2 = { c : 3 };

Object.assignj(traget, souce1, source2);
target // {a : 1, b : 2, c : 3}

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。

如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

var target = {a : 1, b : 2};
var source1 = { b : 2, c : 2};
var source2 = { c : 3};

Objcet.assign(target, source1, source2);
target //{a : 1, b : 2, c :3}

//如果只有一个参数,Object.assign会直接返回该参数。

var obj = {a: 1};
Object.assign(obj) === obj // true

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

var obj1 = {a : {b : 1}};
var obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

*Tips:源对象obj1的a属性的值是一个对象,Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。*

//对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。

var target = {a : {b : 'c', d : 'e'}}
var source = {a : {b : 'hello'}}
Object.assign(target, source);
// {a : { b : 'hello'}}

Object.assign可以用来处理数组,但是会把数组视为对象。

Object.assign([1,2, 3], [4,5]);
//[4,5,3] 

//为属性指定默认值
const DEFAULTS = {
  logLevel: 0,
  outputFormat: 'html'
 };

 function processContent(options) {
    options = Object.assign({}, DEFAULTS, options);
    console.log(options);
    // ...
 }

四.属性的可枚举性和遍历

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。

let obj = { foo : 123}; 
Object.getOwnPropertyDescriptor(obj, 'foo');
//{  
   // value : 123,
   // writable: true,
   //enumerable: true,
   //configurable: true
//}

描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性。

目前,有四个操作会忽略enumerable为false的属性。
for...in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

这四个操作之中,前三个是 ES5 就有的,最后一个Object.assign()是 ES6 新增的。其中,只有for...in会返回继承的属性,其他三个方法都会忽略继承的属性,只处理对象自身的属性。实际上,引入“可枚举”(enumerable)这个概念的最初目的,就是让某些属性可以规避掉for...in操作,不然所有内部属性和方法都会被遍历到。比如,对象原型的toString方法,以及数组的length属性,就通过“可枚举性”,从而避免被for...in遍历到。

另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。

ES6 一共有5种方法可以遍历对象的属性。

for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)。

Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)。

Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性。

Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举。

五. Object.keys(),Object.values(),Object.entries()

ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。

var obj = { foo : 'bar', baz : 42}
Object.keys(obj)
//["foo", "baz"]

ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作为遍历一个对象的补充手段,供for...of循环使用。

let {keys, values, entries} =  object;
let obj = { a : 1, b : 2, c : 3}

for(let key of keys(obj)){
    console.log(key);
    // 'a' , 'b' , 'c'
 }

for(let key of values(obj)){
    console.log(value);
    //1, 2, 3
}

   for(let [key, value] of entries(obj)){
      console.log([key, value]);
      //['a', 1], ['b', 2], ['c', 3]
   }

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。

var obj = { foo : 'bar', baz : 42}
Object.values(obj)
//['bar', 42]

var obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
//["b", "c", "a"]

如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。

Object.values('foo')
 // ['f', 'o', 'o']

Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。

var obj = { foo : 'bar', baz : 42}
Object.entries(obj)
//[['foo', 'bar'], ['baz', 42]]

Object.entries方法的另一个用处是,将对象转为真正的Map结构。

var obj = { foo: 'bar', baz: 42 };
var obj = { foo: 'bar', baz: 42 };
map // Map { foo: "bar", baz: 42 }

六. 对象的扩展运算符

ES2017将扩展运算符(...)引入对象

1.解构赋值

let { x , y , ...z} = {x : 1, y : 2, a : 3, b : 4}

解构赋值必须是最后一个参数,否则会报错。
构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。

let obj = { a : { b : 1}}
let {...x} = obj;
obj.a.b = 2;
x.a.b // 2

扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let z = { a : 3, b : 4}
let n = {...z}

n // { a: 3, b: 4 }

//等同于
let aClone = { ...a }
let aClone = Object.assign({}, a);

扩展运算符可以用于合并两个对象。

 let ab = {...a, ...b}
 //等同于
 let ab = Object.assign({}, a, b);

与数组的扩展运算符一样,对象的扩展运算符后面可以跟表达式。

const obj = {
    ...(x > 1? { a : 1 } : {}),
    b : 2,
};
上一篇 下一篇

猜你喜欢

热点阅读