es6对象扩展

Posted mengxiangji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了es6对象扩展相关的知识,希望对你有一定的参考价值。

属性的简洁表示法

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

let a = 'name'
let obj = {a}
console.log(obj)  // {a: "name"}

上面代码表明,ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。下面是另一个例子。

方法也可以简写

let obj = {
    fn(){
        console.log('aaa')
    }
}

属性名表达式

javascript 定义对象的属性,有两种方法。

    let obj = {};
    obj.name = 1; // 第一种
    obj['a'+'b'] = 2; // 第二种
    console.log(obj) // {name:1,ab:2}

上面代码的方法一是直接用标识符作为属性名(es5),方法二是用表达式作为属性名,这时要将表达式放在方括号之内(es6)。

表达式也可以定义方法名

    let obj = {
        ['a'+'b'](){
            console.log('aaa')
        }
    }
  obj.ab() // aaa

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

方法的name属性

函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。

let obj = {
        fn(){}
    }
  console.log(obj.fn.name) // fn

上面代码中,方法的name属性返回函数名(即方法名)。

如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set。

let obj = {
  get foo() {},
  set foo(x) {}
};
// console.log(obj.foo.name) // TypeError: Cannot read property 'name' of undefined
let descriptor = Object.getOwnPropertyDescriptor(obj,'foo')
console.log(descriptor.get.name) // get foo

有两种特殊情况:bind方法创造的函数,name属性返回bound加上函数的名字;Function构造函数创造的函数,name属性返回

function fn(){

}
console.log(fn.bind().name) // bound fn


console.log(new Function().name) // anonymous

如果对象的方法是一个 Symbol 值,那么name属性返回的是这个 Symbol 值的描述。

let key = Symbol('name')
let obj = {
  [key](){}
}
console.log(obj[key].name) // [name]

属性的可枚举和遍历

  • 可枚举性

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

let obj = {
  name:'1'
}
let descriptor = Object.getOwnPropertyDescriptor(obj,'name')
console.log(descriptor)  // {value: "1", 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一共有5种方法可以遍历对象的属性

  • for...in :循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
  • Object.keys(): 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)的键名
  • Object.getOwnPropertyNames:返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
let obj = {
  name:'1',
  age:11
}
console.log(Object.getOwnPropertyNames(obj)) // ["name", "age"]
  • Object.getOwnPropertySymbols:返回一个数组,包含对象自身的所有 Symbol 属性的键名。
let name = Symbol('mm') 
let obj = {
  [name](){},
  age:11
}
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(mm)]
  • Reflect.ownKeys(obj):返回一个数组,包含对象自身的所有键名,不管键名是Symbol或字符串,也不管是否可枚举
let name = Symbol('mm') 
let obj = {
  [name](){},
  age:11
}
console.log(Reflect.ownKeys(obj)) // ["age", Symbol(mm)]

以上的5种方法遍历对象的键名,都遵守同样的属性遍历的次序规则

  • 首先遍历所有数值减,按照竖直升序排列
  • 其次遍历所有字符串健,按照加入事件升序排列
  • 最后遍历所有Symbol键,按照加入时间排序

super 关键字

我们知道,this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象。

const proto = {
  foo: 'hello'
};

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

Object.setPrototypeOf(obj, proto);
console.log(obj.find()) // "hello"

上面代码中,对象obj.find()方法之中,通过super.foo引用了原型对象proto的foo属性。

注意,super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。

对象的扩展运算符

对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面

let {a,...b} = {a:1,b:2,c:3,d:4}
console.log(a,b)  // 1 {b: 2, c: 3, d: 4}

解构赋值必须是最后一个参数,否则会报错。

注意,解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。

let obj = {a:1,b:{c:2}}
let {a,...x} = obj
obj.b.c = 222;
console.log(x)  // {b: {c: 222}}

以上是关于es6对象扩展的主要内容,如果未能解决你的问题,请参考以下文章

ES6 对象的扩展

ES6 - 对象扩展(增强字面量)

es6~扩展运算符后续

es6数组的扩展

ES6正则扩展

函数的扩展--ES6