ES6对象属性名简洁表示法和表达式、对象新方法、属性的遍历 概览

对象属性的简洁表示法

ES6允许直接写入变量和函数作为对象的属性和方法。
ES6允许在对象中只写属性名,不写属性值。

let foo = 'bar';
let baz = {foo};
console.log(baz); // {foo:'bar'}
// same as
let baz1 = {foo:foo}
console.log(baz1); // {foo:'bar'}

let first = 'Jone';
let last = 'Doe';
let obj = {first,last};
console.log(obj); // {first: "Jone", last: "Doe"}
// same as
let obj1 = {first:first,last:last};
console.log(obj1); // {first: "Jone", last: "Doe"}

const HELLO = {
  method(){
    return 'hello'
  }
}
console.log(HELLO.method()); // 'hello'
// same as
const HELLO1 = {
  method:function(){
    return 'hello'
  }
}
console.log(HELLO1.method()); // 'hello'

实际运用中的一些例子:

// 用于人物名称及行为的对象
let birth = '2000/01/01'
const PERSON = {
  name: '张三',
  birth, // same as: birth:birth
  hello() {console.log('我的名字是', this.name);}
  // same as: hello:function(){...}
}

// 用于函数返回值
function getPoint(x = 1, y=10){
  return {x, y}
}
console.log(getPoint()); // {x: 1, y: 10}
console.log(getPoint(3,3)); // {x: 3, y: 3}
console.log(getPoint(3)); // {x: 3, y: 10}

// CommonJS模块输出变量
let ms = {};
function getItem(key){
  return key in ms? ms[key] : null;
}
function setItem(key,value){
  ms[key] = value;
}
function clear(){
  ms = {};
}
module.exports = {getItem,setItem,clear};
// same as: module.exports = {getItem:getItem,setItem:setItem,clear:clear};

// 属性的赋值器和取值器
const CART = {
  _wheels: 4,
  get wheels(){
    return this._wheels;
  },
  set wheels(value){
    if(value<this._wheels){
      throw new Error('数值太小了');
    }
    this._wheels = value;
  }
}

属性名表达式

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

定义对象属性的两种方法:

  • 通过固定名称
let obj = {};
obj.foo = true;
console.log(obj); // {foo: true}
  • 通过表达式
let obj1 = {};
obj1['a'+'bc'] = 123;
console.log(obj1); // {abc: 123}
let propKey = 'foo';
let propKeyObj = {
  [propKey]: true,
  ['a'+ 'bc']: 123
}
console.log(propKeyObj); // {foo: true, abc: 123}

let lastWord = 'last word';
let a = {
  'first word':'hello',
  [lastWord]:'world'
}
console.log(a); // {first word: "hello", last word: "world"}
console.log(a['first word']);// 'hello'
console.log(a[lastWord]); // 'world'
console.log(a['last word']); // 'world'

// 定义方法名
let methodName = {
  ['h'+'ello'](){
    return 'hi'
  }
}
console.log(methodName.hello()); // 'hi'

注意:属性名表达式不能和简洁表达式同时使用

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

注意:属性表达式如果是一个对象,默认情况下会把对象转为字符串[object Object]

const keyA = {a:1};
const keyB = {b:2};
const myObject = {
  [keyA]: 'valueA',
  [keyB]: 'valueB',
}
console.log(myObject); // {[object Object]: "valueB"}

Object.is(value1,value2)

与严格相等运算符(=)的行为基本一致;
解决严格运算符(
=)NaN不等于自身,以及+0等于-0的问题。

console.log(Object.is('foo','foo'));; // true

console.log({} === {}); // false
console.log(Object.is({},{})); // false

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

console.log(+0 === -0); // true
console.log(Object.is(+0,-0)); // false

console.log([0,NaN,2].indexOf(NaN)); // -1
console.log([0,NaN,2].findIndex(x => Object.is(x, NaN))); // 1

Object.assign(target,source_1,source_2,...)

Object.assign()方法将源对象(source)所有可枚举的属性合并到目标对象(target)中:它修改target,首先将source_1的所有可枚举的自己的属性复制到target中,然后将source_2的所有自己的属性复制到target中,以此类推。最后,它返回target。

let target = {a:1};
let source_1 = {b:2};
let source_2 = {c:3};
Object.assign(target,source_1,source_2);
console.log(target,source_1,source_2); // {a: 1, b: 2, c: 3} {b: 2} {c: 3}

让我们更仔细看看Object.assign()是如何运作的:

  • 两种类型的属性键:同时支持StringSymbel作为属性键;
let v1 = 'abc';
let v2 = true;
let v3 = 10;
let v4 = {[Symbol('c')]: 'c'};
const obj = Object.assign({}, v1, v2, v3, v4);
console.log(obj); // {0: "a", 1: "b", 2: "c", Symbol(c): "c"}
  • 仅复制源对象可枚举的自身属性:不复制继承属性,也不复制不可枚举的属性;
const obj = Object.assign({b: 'c'},
    Object.defineProperty({}, 'invisible',{
      enumerable:false, // enumerable属性称为‘可枚举性’
      value:'hello'
    })
)
console.log(obj); // {b: "c"}
  • 通过赋值复制:目标对象中的属性是通过赋值(内部操作[[Put]])创建的。这意味着,如果target拥有(自己的或继承的)setter,则在复制期间将调用这些setter。另一种方法是定义新的属性,这是一种总是创建新的自己的属性且从不调用setter的操作。最初有人建议使用Object.assign()的一个变体,它使用定义而不是赋值的方式。这个提议在ECMAScript 6中已经被拒绝了,但是在以后的版本中可能会被重新考虑。
let obj1 = {a: {b: 1}};
let obj2 = Object.assign({}, obj1);
console.log(obj2); // {a: {b: 1}} 

// Object.assign()方法实行的是浅复制,而不是深复制。
let target = {a: { b: 'c', d: 'e' }};
let source = {a: { b: 'hello' }};
const obj = Object.assign(target, source);
console.log(obj); // a: {b: "hello"}
console.log(target); // a: {b: "hello"}

常见用途:
为对象添加属性

class Point{
  constructor(x, y){
    Object.assign(this, {x, y});
  }
}

为对象添加方法

function SomeClass(){
  
}
Object.assign(SomeClass.prototype, {
  someMethod(arg1,arg2){
    // ...
  },
  anotherMethod(){
    // ...
  }
})
console.dir(SomeClass);

// same as
SomeClass.prototype.someMethod = function(arg1, arg2){
  //...
};
SomeClass.prototype.anotherMethod = function(){
  //...
}

克隆对象

// 克隆原始对象自身的值
function clone1(origin){
  return Object.assign({}, origin);
}

// 克隆原始对象继承的值(保持继承链)
function clone2(params) {
  let paramsProto = Object.getPrototypeOf(params);
  return Object.assigin(Object.create(paramsProto), params)
}

合并多个对象

// 多个对象合并到target
const merge1 = (target, ...sources) => Object.assign(target, ...sources);
// 多对象合并返回新对象
const merge2 = (...sources) => Object.assign({}, ...sources);

为属性指定默认值

const DEFAULTS = {
  logLevel: 0,
  output: 'html'
};
function processContent(options){
  options = Object.assign({},DEFAULTS,options);
  console.log(options);
}
processContent('abc'); // {0: "a", 1: "b", 2: "c", logLevel: 0, output: "html"}
processContent({'abc':'abc'}); // {logLevel: 0, output: "html", abc: "abc"}

属性的遍历

for...inObject.keys(obj)Object.getOwnPropertyNames(obj)Object.getOwnPropertySymbels(obj)Reflect.ownKeys(obj)

function allObj(){
  this.name = '张三'; // 自有属性
  this.age = '12'; // 自有属性
  this.invisible = {
    enumerable: false,
    value: 'hello'
  },
  this.invisible = {
    enumerable: false,
    value: 'hello'
  }
}
allObj.prototype.disEnum = {
  enumerable: false,
  value: 'disEnum'
}
allObj.prototype.Enum = {
  enumerable: true,
  value: 'Enum'
}
let obj = new allObj
Object.assign(obj, {
  a: '1',
  b: '2',
  c: '3',
  [Symbol('c')]: 'c',
})
// let obj2 = Object.assign(obj1,
//   Object.defineProperty({}, )
// )
Object.assign(obj,
  Object.defineProperty({}, 'visible',{
    enumerable: true,
    value: 'word'
  })
)
console.log(obj); // allObj {a: "1",age: "12",b: "2",c: "3",invisible: {enumerable: false,value: 'hello'},name: "张三",visible: "word",Symbol(c): "c",__proto__:Enum: {enumerable: true, value: "Enum"},disEnum: {enumerable: false, value: "disEnum"}}
// for...in循环遍历对象自身的和继承的属性(不含Symbol属性)
for(let key in obj){
  console.log(key);
  // name
  // age
  // invisible
  // a
  // b
  // c
  // invisible
  // visible
  // disEnum
  // Enum
}

// Object.keys()返回一个数组,包括对象自身(不含继承的)的所有属性(不含Symbol属性)
console.log(Object.keys(obj)); // ["name", "age", "invisible", "a", "b", "c", "visible"]

// Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性 )
console.log(Object.getOwnPropertyNames(obj)); // ["name", "age", "invisible", "a", "b", "c", "visible"]

// Object.getOwnPropertySymbols() 返回一个数组,包含所有对象自身的所有Symbol属性
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(c)]

// Reflect.ownKeys()返回一个数组,包含对象自身的所有属性,不管属性名是Symbol还是字符串,也不管是否可枚举
console.log(Reflect.ownKeys(obj)); // ["name", "age", "invisible", "a", "b", "c", "visible", Symbol(c)]

ES6对象属性名简洁表示法和表达式、对象新方法、属性的遍历