对象的扩展

引用自http://es6.ruanyifeng.com/#docs/object

属性的简洁写法

  • ES6允许在大括号里,直接写入变量和函数,作为对象的属性和方法,更加简洁

    属性简写
    function f(foo,bar){
        return (foo,bar)
    }
    f(1,2)//{foo:1,bar:2}
    这时属性名就是变量名,属性值就是变量值
    
    方法简写
    const foo ={
        bar(){
            return 'baz'
        }
    }
    
    const cart = {
        _wheels: 5,
        get wheels() {
            return this._wheels;
        },
        set wheels(value) {
            if (value < this._wheels) {
                throw new Error('数值太小了!');
            }
            this._wheels = value;
        }
    }
    //setter属性的赋值器,getter属性的取值器
    //set 下wheels大于_wheels时,返回这个值
    //小于时,抛错
    console.log(cart.wheels = 6)
    

属性名表达式

  • js定义对象的属性,有两种方法

    1.直接使用标识符作为属性名

    2.用表达式作为属性名

    方法1var  obj = {
        foo:true,
        abc:123
    }
    方法2let foo = 'foo';
    let obj ={
        [foo]:true,
        ['a'+'bc']:123
    }
    ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。
    
  • 表达式还可以定义方法名

    let obj ={
      ['h'+'ello'](){
          return 'hi'
      }
    }
    obj.hello()//hi
    
  • 属性名与简洁表示法不能同时使用,会报错

    // 报错
    const foo = 'bar';
    const bar = 'abc';
    const baz = { [foo] };
    
  • 属性名表达式如果是一个对象,默认将对象转为[object Object]

       const keyA = {a:1}
       const  keyB = {b:2}
       const myObject = {
             [keyA]:'valueAa',
             [keyB]:"valueBb"
                }
     console.log(myObject)//{[object Object]: "valueBb"}
    //[keyA]和[keyB]得到的都是[object Object],所以[keyB]覆盖了[keyA]
    

方法的name属性

  • 函数的name属性,返回函数名。对象方法也是韩式们也有name

    // const person ={
             sayName(){
             console.log('hello!')
                	   }
             }
             console.log(person.sayName.name)//sayName  返回函数名
    
  • 如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,

    而是该方法的属性的描述对象的get和set属性上

    
             const obj = {
                 get foo() { },
                 set foo(x) { }
             }
             console.log(obj.foo.name)//Uncaught TypeError
            Object.getOwnPropertyDescriptor(obj, prop)
            //obj:需要查找的目标对象
            //prop:目标对象内属性
    
  • 2种特殊情况;bind方法创造的函数,

    name属性返回bound加函数名;

    Function构造函数创造的函数,name属性返回

    var foo= (new Function()).name
     console.log(foo)//anonymous
     var dosth = function(){ 
     }
     console.log(dosth.bind().name)//bound dosth
    
  • 如果对象的方法时一个Symbol值,name属性返回的是这个Symbol值的描述

         const key1 = Symbol('desc')
                const key2 = Symbol();
                let obj = {
                    [key1](){},
                    [key2](){},
                }
                console.log(obj[key1].name)//[desc]
                console.log(obj[key2].name)//''
    

属性的可枚举性和遍历

属性的可枚举性
  • 对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为

    Object.getOwnPropertyDescriptor方法可以获取改属性的描述对象,

          let obj ={foo:123}
           var baz =  Object.getOwnPropertyDescriptor(obj,"foo")
           //{
           	configurable: true//可枚举性,如果该属性为false,表示某些操作会忽略当前属性
    		enumerable: true
    		value: 123
    		writable: true
           }
     /*configurable: false时,
     目前有4个操作会忽略enumerable为false的属性
     for..in循环:只是遍历对象自身的和集成的可枚举的属性
     Object.keys():返回对象自身的虽有可枚举的属性的键名
     JSON.stringify():只串行化对象自身的可枚举的属性
     object.assin()只拷贝对象自身的可枚举属性	 
     
     这4个操作,前3个时ES5就有的,最后一格Object.assign()是ES6新增的
     其中,
     只有for...in会返回继承的属性,其他三个方法都会忽略继承的属性,只处理自身的属性
     
     */   
           操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不要用for...in循环,而用Object.keys()代替。
    
属性的遍历

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

  • for…in:循环遍历对象自身的和集成的可枚举属性(不含Symbol属性)

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

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

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

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

    以上5种方法属性遍历的次序规则:

    首先遍历所有数值键,按照数组升序排列
    其次遍历所有字符串键,按照加入时间升序排列
    最后遍历所有Symbol键,按照加入时间升序排列

var bar = Reflect.ownKeys({[Symbol()]:0,b:0,10:0,2:0,a:0})
      console.log(bar)// ["2", "10", "b", "a", Symbol()]

super关键字

this关键字总是指向函数所在的当前对象

ES6新增 super关键字,指向当前对象的原型对象

const proto ={
        foo:"hello"
    };
    const obj ={
        foo:'world',
        find(){
            return super.foo
        }
    Object.setPrototypeOf(obj,proto)//Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或  null
    //此时obj的原型指向proto,所以super.foo为proto中的foo
    console.log(obj.find())//hello

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

目前只有对象方法的简写可以让js引擎确认,定义的是对象的方法,从而可使 用super

对象的扩展运算符

  • ES2018将(…)扩展运算符引用入到对象中
结构赋值
  • 对象的结构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable),但尚未被读取的属性,分配到指定的对象上面。所有的键和值都会拷贝到新对象上

        let {x,y,...z} = {x:1,y:2,a:3,b:4}//{x: 1, y: 2, a: 3, b: 4}
        //变量z是结构赋值所在的对象,它过去等号右边的所有尚未读取的键(a和b)将它们连同值一起拷贝过来
    

    注:由于解构赋值要求等号右边是一个对象,所以如果等号右边是undefined或者 null就会报错,因为它们无法转为对象

  • 结构赋值必须是最后一个参数,否则报错 Rest element must be last element

  • 解构赋值的拷贝是浅拷贝了,即当一个键的值是复合类型的值(数组,对象,函数)那么结构

    赋值拷贝的是这个值的引用,而不是这个值的副本

  • 扩展运算符的结构赋值,不能赋值继承自原型对象的属性

    let o1 = {a:1};
            let o2 = {b:2};
            o2.__proto__ = o1;
            let {...o3} = o2;
    
            console.log(o2.a)//1 02的原型__proto__指向了o1
            console.log(o3)//{b: 2}//o3复制了o2,但是只复制了o2本身的属性,没有复制它的原型对象o1的属性
    
    Object.create(proto[,propertiesObject])
    //创建一个新对象,使用现有的对象来提供新创建的对象的proto
    参数:
    proto : 必须。表示新建对象的原型对象,即该参数会被赋值到目标对象(即新对象,或说是最后返回的对象)的原型上。该参数可以是null, 对象, 函数的prototype属性 (创建空的对象时需传null , 否则会抛出TypeError异常)。
    
    propertiesObject : 可选。 添加到新创建对象的可枚举属性(即其自身的属性,而不是原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。
    3 返回值:
    在指定原型对象上添加新属性后的对象。
    
            const o = Object.create({x:1,y:2});
            o.z=3
            console.log(o){z: 3}
                   /* z: 3
                      __proto__:
                      x: 1
                      y: 2    */
            let {x,...newObj} = o
            let {y,z}=newObj
            console.log(x,y,z)//1 undefined 3
    变量x只是单纯的结构赋值,可以读取o继承的属性得到x=1;
    变量y,z是扩展运算符的解构赋值,只能读取o自身的属性,所以变量z可以赋值成功,
    而y取不到值
    
  • ES6规定,变量声明语句之中,如果使用解构赋值,扩展运算符后面必须是一个变量名

    而不能是一个解构赋值表达式,

    所以上式中 let {x,…{y,z}} = o //报错

  • 结构赋值的用处是扩展某个函数的参数,引入其他操作

扩展运算符
  • 对象的扩展运算符(…)用于去除参数对象的所有可比案例属性,拷贝到当前对象之中

  • 数组是特殊的对象,所以对象的扩展运算符也可以用于数组

       let foo ={...['a','b','c']}
       console.log(foo)//{0: "a", 1: "b", 2: "c"}
    
  • 如果扩展运算符后面是一个空对象,则没有任何效果

    	let foo = {...{},a:1}
        console.log(foo)//{a: 1}
    
  • 如果扩展运算符后面不是对象,则自动将其转为对象

    	// 等同于 {...Object(1)}
    	{...1} // {}
    //扩展运算符后面是整数1,会自动转为数值的包装对象Number{1}。
    //由于该对象没有自身属性,所以返回一个空对象。
    
  • 如果扩展运算符后面是字符串,自动转成一个类似数组的对象,返回的不是空对象

     		let foo ={...'foo'}
            console.log(foo)//{0: "f", 1: "o", 2: "o"}
    
  • 对象的扩展运算符等同于使用Object.assign()方法

            let a ={baz:1}
                let foo = {...a}
                let bar = Object.assign({},a)
       
            console.log(foo,bar)//{baz: 1} {baz: 1}
    	//Object.assign() 
    	//Object.assign(target, ...sources) target:目标参数, sources:源对象
    	//用于将所有可枚举属性的值从一个或多个源对象复制到目标对象
       
    
  • 扩展运算符可以用于合并两个对象

      let a = { foo: 1 }
            let b = { bar: 2 }
            let ab = { ...a, ...b }
            console.log(ab)//{foo: 1, bar: 2}
            Object.assign({}, a, b) //{ foo: 1, bar: 2 }
    
  • 可用来修改现有对象的部分属性

             let oldV={
                    age:23
                }
                let newV = {
                    ...oldV,
                    name:"liu"
                }
                console.log(newV)//{age: 24, name: "liu"}
    
  • 与数组的扩展运算符一样,对象的扩展运算符后也可以跟表达式

       			let x =0
                const obj ={
                    ...(x>1?{a:1}:{}),b:2
                }
                console.log(obj)//{b: 2}
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值