Skip to content

Latest commit

 

History

History
222 lines (182 loc) · 5.74 KB

10对象的扩展.md

File metadata and controls

222 lines (182 loc) · 5.74 KB

对象的扩展

1.属性的简洁表示法

  1. 属性简写
  2. 方法简写
  3. 返回值简写
var a = 'a'
const o = {
  a,
  method() {
    var x = 1
    return {x}
  }
};

2.属性名表达式

let propKey = 'foo';

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

注意,如果属性名表达式是对象,默认情况下会自动将对象转为字符串[object Object]

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

const myObject = {
  [keyA]: 'valueA',
  [keyB]: 'valueB'
};

myObject // Object {[object Object]: "valueB"}

3.方法的 name 属性

  1. 正常函数:fn.name
  2. bind函数:bound + fn.name
  3. Function构造函数:anonymous
  4. 对象的getter函数和getter函数:Object.getOwnPropertyDescriptor(obj, 'foo').get.name
  5. 对象属性名为Symbol的函数:Symbol 值的描述
// 1.正常函数:fn.name
(function a(){}).name // "a"

// 2.bind函数:bound + fn.name
(function a(){}).bind().name // "bound a"

// 3.Function构造函数:anonymous
(new Function()).name // "anonymous"

// 4.对象的getter函数和getter函数:Object.getOwnPropertyDescriptor(obj, 'foo').get.name
const obj = {
  get foo() {},
  set foo(x) {}
};

obj.foo.name // TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"

// 5.对象属性名为Symbol的函数:Symbol 值的描述
const key1 = Symbol('description');
const key2 = Symbol();
let obj = {
  [key1]() {},
  [key2]() {},
};
obj[key1].name // "[description]"
obj[key2].name // ""

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

通过Object.getOwnPropertyDescriptor(obj, 属性)可以获取该对象属性的描述对象。 描述对象中有 enumerable 属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性。

有四个操作会忽略enumerable为false的属性( ES6 规定,所有 Class 的原型的方法都是不可枚举的。)

  • for...in循环:遍历对象自身的和继承可枚举属性(不含 Symbol 属性
  • Object.keys():返回对象自身的所有可枚举的属性的键名
  • JSON.stringify():只串行化对象自身可枚举的属性
  • Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身可枚举的属性

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

  1. for...in:遍历对象自身的和继承可枚举属性(不含 Symbol 属性
  2. Object.keys(obj):返回数组,包括对象自身的所有可枚举的属性的键名(不含 Symbol 属性
  3. Object.getOwnPropertyNames(obj):返回数组,包含对象自身的所有属性的键名(不含 Symbol 属性
  4. Object.getOwnPropertySymbols(obj):返回数组,包含对象自身所有 Symbol 属性的键名
  5. Reflect.ownKeys(obj):返回数组,包含对象自身的所有键名(包含 Symbol 属性

规律: Reflect.ownKeys > Object.getOwnPropertyNames(非Symbol) > Object.keys(非Symbol可枚举) Reflect.ownKeys > Object.getOwnPropertySymbols(仅Symbol)

排序

  1. 数值键:数值升序排列
  2. 字符串:加入时间升序排列
  3. Symbol键:加入时间升序排列
Reflect.ownKeys({ 10:0, 2:0, b:0, a:0, [Symbol('a')]:0, [Symbol('b')]:0}) //["2", "10", "b", "a", Symbol(a), Symbol(b)]
Reflect.ownKeys({ 10:0, 2:0, a:0, b:0, [Symbol('b')]:0, [Symbol('a')]:0}) //["2", "10", "a", "b", Symbol(b), Symbol(a)]

5.super 关键字

  1. this指向函数所在的当前对象
  2. super指向当前对象的原型对象
const proto = {
  x: 'hello',
  foo() {
    console.log(this.x);
  },
};

const obj = {
  x: 'world',
  foo() {
    super.foo();
  }
}

Object.setPrototypeOf(obj, proto);

obj.foo() // "world"

6.对象的扩展运算符

克隆一个对象,还拷贝对象原型的属性

// 写法二
const clone2 = Object.assign(
  Object.create(Object.getPrototypeOf(obj)),
  obj
);

// 写法三
const clone3 = Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
)

6.1 解构赋值

  1. 解构必须是对象
  2. 赋值变量必须最后一个参数
  3. 赋值变量是浅拷贝
  4. 扩展运算符不能取继承自原型对象的属性,但是解构赋值可以
// 1. 解构必须是对象
let { ...z } = null; // 运行时错误
let { ...z } = undefined; // 运行时错误

// 2. 赋值变量必须最后一个参数
let { ...x, y, z } = someObject; // 句法错误
let { x, ...y, ...z } = someObject; // 句法错误

// 3. 赋值变量是浅拷贝
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2

// 4. 赋值变量不能取继承自原型对象的属性
const o = Object.create({ x: 1, y: 2 });
o.z = 3;

let { x, ...newObj } = o;
let { y, z } = newObj;
x // 1
y // undefined
z // 3

6.2 扩展运算符

等同于使用Object.assign()方法

  1. 基本类型会转为对象
  2. 扩展运算符的参数是对象,如果有取值函数get,这个函数是会执行的
{...1} // {}

{...true} // {}

{...undefined} // {}

{...null} // {}

{...'hello'} //{0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}

var a = {a: 1}
var b = {b: 2}
let ab = { ...a, ...b } // {a: 1, b: 2}

{ ...['a', 'b', 'c'] } // {0: "a", 1: "b", 2: "c"}
// 并不会抛出错误,因为 x 属性只是被定义,但没执行
let aWithXGetter = {
  ...a,
  get x() {
    throw new Error('not throw yet');
  }
};

// 会抛出错误,因为 x 属性被执行了
let runtimeError = {
  ...a,
  ...{
    get x() {
      throw new Error('throw now');
    }
  }
};