美文网首页
Es6对象新方法

Es6对象新方法

作者: 牛大嘴 | 来源:发表于2018-12-20 08:20 被阅读0次
    Object.freeze()
    该方法可以冻结一个对象,冻结对象指的是不能向这个对象,添加属性、删除属性、修改属性、以及不能修改该对象已有属性的可枚举型、可写性、可配置性,该方法返回被冻结的对象。
    演示:
    var json = {
      name:'秦司令'
    };
    var obj = Object.freeze(json);
    obj.age = 20;        // 不生效
    obj.name = 'abc';   //不生效
    delete obj.name    // 不生效
    console.log(obj.name);  //秦司令 
    console.log(obj.age)  // undefined
    

    上面代码给大家展示了一下操作 就是防止对象的属性被修改 , 对象属性的可枚举性、可写性、可配置性、下面我们会说到。


    Object.is()
    Es5比较两个值是否相等,只有两个运算符 ,一个等于运算符( == ) , 一个严格等于运算符( === ) 。它们都有缺点,前者会自动转换类型 , 后者的NaN不等于自身,以及+0 等于 -0。javascript缺乏一种运算,在所有环境中,你们的值是一样的就应该相等。
    Es6提出同值相等算法,用来解决这个问题。
    Object.is就是部署这个算法的新方法。它用来比较俩个值是否严格相等,与严格运算符(===) 的行为基本一致。
    演示:
    Object.is('foo','foo') // true
    Object.is({},{}) // false
    

    上面代码中两个空对象不相等,因为它们的引用地址不同。
    不同之处只有两个: 一是 +0 不等于 -0 , 二是 NaN 等于自身

    // Es5写法
    +0  === -0 // true
    NaN === NaN  //false
    
    //Es6提出的新算法方法
    Object.is(+0,-0) //false
    Object.is(NaN,NaN) // true
    

    上面代码Object.is Es6新提出的算法 让 NaN 等于自身


    Object.assign()
    该方法用于对象合并,将源对象(source)的所有可枚举属性,复制到target目标对象里。
    演示:
    var json = {a:1};
    var source = {b:2};
    Object.assign(json,source)  // {a:1,b:2}
    

    Object.assign方法的第一个参数是目标对象,其它的都是源对象,该方法返回值返回第一个参数。

    注意,如果目标对象和源对象的属性有重复的话,那么源对象的属性覆盖目标对象的属性。

    var json = {a:1,b:1}
    var source = {b:2,c:3}
    Object.assign(json,source) // {a:1,b:2,c:3}
    

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

    Object.assign({name:'秦司令'}) // {name:'秦司令'}
    

    如果该参数不是对象,而先会转换成对象。

    Object.assign(2) // Number({}) 
    

    由于undefined和null无法转换成对象,所以如果它们作为参数,就会报错。

    Object.assign(undefined) //报错
    Object.assign(null)  //报错
    

    当然,如果undefined和null不在首参数就不会报错,因为它们不在首参数,处理方法就不同,如果无法转换成对象就会跳过。

    Object.assign({},123,{name:'秦司令'}) // {name:'秦司令'}
    

    其它类型的值 数字,布尔,字符串,不在首参数内也不会报错 。但是,除了字符串会以数组的形式,拷贝到目标对象里,其它值都不行,只有字符串可以。

    Object.assign({},'str') // {0:'s',1:'t',2:'r'} 
    Object.assign({},123) // {}
    Object.assign({},true) // {}
    

    上面代码中,数值,布尔值,字符串 结果只有字符串被拷贝进去,这是因为只有字符串有包装类对象,会产生可枚举属性。

    请看下个列子

    Object(true)  //{ [[PrimitiveValue]]:true }
    Object(123)  // { [[PrimitiveValue]]:123 }
    Object('str') // {0:'s',1:'t',2:'r',length:3, [[PrimitiveValue]]:'str' }
    

    上面代码看对象的返回值 [[PrimitiveValue]] 这个是原始属性 assign 是无法拿到的,只有字符串有可枚举属性,所以上面只能拷贝字符串。

    Object.assign拷贝属性也是有限制的,只拷贝源对象的自身属性(不包含继承属性),也不拷贝不可枚举属性(enumerable:false)。

    Object.assign({name:'秦司令'},
      Object.defineProperty({},'age',{
        enumerable:false,
        value:20  
      })
    )
    

    上面代码中,Object.assign要拷贝这个对象属性,但是没有被拷贝进去,因为这个属性里面设置了不可枚举属性,enumerable:false。

    属性名为Symbol值的也会被拷贝进去

    Object.assign({a:'b'},{[Symbol()]:'c'}) // {a:'b',[Symbol()]:'c'}
    

    注意点

    浅拷贝
    Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性发生改变,那么Object.assign的目标对象也跟着改变。
    var json = {a:{b:1}}
    var obj = Object.assign({},json)
    json.a.b = 2
    obj.a.b // 2
    

    上面代码发生引用的原因是,json.a的属性值是一个对象,Object.assign拷贝到的是这个对象的引用,这个对象的任何变化,都会映射到目标对象上

    数组的处理
    Object.assign用来处理数组,会把数组视为对象处理。
    Object.assign([1,2,3],[4,5,6]) // [4,5,6]
    

    上面代码中,Object.assign把数组视为属性名为 0 1 2的对象,因此源数组的0号属性 4 覆盖了 目标属性的 1 值 , 以此类推 最后全部覆盖。

    取值函数的处理
    Object.assign只能进行值的复制,如果是要复制一个取值函数,那么将求值后再复制
    const source = {
      get foo(){
        return 1
      }
    }
    const target = {};
    Object.assign(target,source)  // {foo:1}
    

    上面代码中,source对象的foo属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值复制过去


    常见用途

    Object.assign方法有很多好处。
    一、为对象添加属性
    class Point{
      constructor(x,y){
        Object.assign(this,{x,y})
      }
    }
    new Point(1,2)
    

    上面方法通过Object.assign方法,将x属性和y属性添加到Point类的对象实例。

    二、给对象添加方法
    function Fn(){}
    Object.assign(Fn.Prototype,{
      add(){
      
      }
    })
    new Fn()
    

    上面代码使用Object.assign方法给对象添加方法,这样写法简洁表达式

    三、克隆对象
    function clone(obj){
      return Object.assign({},obj)
    }
    

    上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。

    不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值,如果想要克隆它的原型,请看下列代码。

    function clone(){
      var proto = Object.getPrototypeOf(obj)
      return Object.assign(Object.create(proto),obj)
    }
    // Object.create方法是操作__proto__ 
    
    四、合并多个对象

    将多个对象合并到某个对象

    const mer = (target,...source) => Object.assign(target,...source)
    //上面的写法 相当于下面
    function Demo(target,...source){
      return Object.assign(target,...source)
    }
    

    Object.getOwnPropertyDescriptors()
    Es5的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor) , Es2017引入了Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象。
    const obj = {
      foo:123,
      get bar(){
        return 'aaa'
      }
    }
    Object.getOwnPropertyDescriptors(obj)
    //{ foo:
    //    { value: 123,
    //      writable: true,
    //      enumerable: true,
    //      configurable: true },
    //   bar:
    //    { get: [Function: get bar],
    //      set: undefined,
    //      enumerable: true,
    //      configurable: true } }
    

    上面代码中,Object.getOwnPropertyDescriptors()方法返回一个对象,所有原对象的属性名都是该对象的属性名,对应的属性值就是该对象的描述对象。

    该方法的引入,主要是为了解决Object.assign不能正常拷贝 set属性 和 get 属性的取值函数。

    const source = {
        set foo(value){
          console.log(value)
        }
    }
    var obj = Object.assign({},source);
    Object.getOwnPropertyDescriptor(obj,'foo')
    // { value: undefined,
    //   writable: true,
    //   enumerable: true,
    //   configurable: true }
    

    上面代码中,source对象的foo属性的值是一个赋值函数,Object.assign方法将这个属性拷贝给target1对象,结果该属性的值变成了undefined,这是因为Object.assign方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法。

    这时,Object.getOwnPropertyDescriptors()方法配合Object.defineProperties方法,就可以实现正确拷贝。

    const source = {
      set foo(value){
        console.log(value)
      }
    }
    var target = {}
    Object.defineProperties(target,Object.getOwnPropertyDescriptors(source)) 
    Object.getOwnPropertyDescriptor(target,'foo')
    

    上面的代码,将属性描述对象添加到目标对象里面。

    下面讲解一下Object.defineProperties该方法

    var json = {
      get foo(){
        return 123
      }
    };
    Object.defineProperties({},Object.getOwnPropertyDescriptors(json)) ;
    //上面的写法,等同于下面的写法
    Object.defineProperties({},{
      foo:{
         get(){
            return 123;
         },
         set(value){
            return value;
         }
      }
    });
    

    上面代码, json是一个对象,里面是一个取值函数 ,然后下面通过对象的属性描述方法给它添加到Object.defineProperties该方法里面。

    另外,Object.getOwnPropertyDescriptors()方法的另一个用处,是配合Object.create() 方法,将对象属性克隆到一个新对象,这是浅拷贝。

    var obj = {
      name:'秦司令'
    };
    Object.create(Object.getPrototypeOf(obj),Object.getOwnPropertyDescriptors(obj));
    

    __ proto __ 属性(前后各两个下划线),用来读取或设置当前对象的prototype对象。目前,所有浏览器(包括IE11) 都部署了这个属性。
    演示:
    //Es5的写法
    function demo(){}
    var obj  =  {
        method:function(){}
    }
    obj.__ proto __ = demo
    new demo() 
    
    // Es6的写法
    
    var obj  = Object.create(demo)
    

    上面代码中,Es6的写法Object.create该方法直接是设置__ proto __ 属性的

    该属性没有写入Es6的正文,而是写入了附录,原因是__ proto __前后的双下划线,说明它本质上是一个内部属性,而不是一个正式对外的API,只是由于浏览器广泛支持,才被加入Es6。标准明确规定,只有浏览器必须部署这个属性,其它运行环境不一定要部署。

    Object.getPrototypeOf()
    该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
    演示:
    var obj = {}
    Object.getPrototypeOf(obj) 
    

    下面是一个列子。

    function Fn(){}
    var f = new Fn()
    Object.getPrototypeOf(f) === Fn.prototype  //true
    Object.setPrototypeOf(f,Object.prototype)
    Object.getPrototypeOf(f) === Fn.prototype //false
    

    如果参数不是对象,会自动转换为对象

    Object.getPrototypeOf(1)
    // 转换过程 Object.getPrototypeOf(Number(1))
    // Number{ [[PrimitiveValue]]: 0 }
    Object.getPrototypeOf('foo')
    //转换过程 Object.getPrototypeOf(String('foo'))
    // String{length:0,[[PrimitiveValue]]: ' ' }
    
    Object.getPrototypeOf(1) == Number.prototype  // true
    Object.getPrototypeOf('foo') == String.prototype // true
    

    如果参数是undefined和null,它们无法转换为对象,会直接报错

    Object.getPrototypeOf(null)   //报错
    // typeError: Cannot convert null or undefined to Object
    Object.getPrototypeOf(undefined)  //报错
    // typeError: Cannot convert null or undefined to Object
    

    如果一个对象本身部署了__ proto __属性,该属性的值就是对象的值。

    Object.getPrototypeOf({__proto__:null}) // null 
    

    Object.setPrototypeOf()
    Object.setPrototypeOf方法的作用与__ proto __ 相同, 用来设置一个对象的prototype对象,返回参数对象本身。它是Es6正式推荐设置原型的对象的方法。
    演示:
    //格式
    Object.setPrototypeOf(object,prototype)
    //用法
    const obj = Object.setPrototypeOf({},null) //设置这对象没有原型
    
    //该方法等同于下面的函数
    function setPrototypeOf(obj,proto1){
      obj.__proto__ = proto1
      return obj
    }
    

    下面是一个例子

    let proto = {}
    let obj = {name:'秦司令'}
    Object.setPrototypeOf(obj,proto)
    
    proto.x = 10;
    proto.y = 20;
    
    obj.name // 秦司令
    obj.x // 10
    obj.y // 20
    

    上面代码将proto对象设为obj的原型,所以从obj对象可以读取proto对象的原型属性。

    如果第一个参数不是对象,会自动转换为对象,但是由于返回的还是第一个参数,这个操作不会产生任何效果。

    Object.setPrototypeOf(1,{})  === 1
    Object.setPrototyoeOf('name' , {}) == 'name'
    Object.setPrototypeOf(true,{}) == true
    

    由于undefined和null无法转换为对象,所以第一个参数是undefined或null的话,会直接报错。

    Object.setPrototypeOf(undefined,{}) //报错
    Object.setPrototypeOf(null,{}) //报错
    
    Object.keys()
    Es5引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不包含继承的) 所有可遍历(enumerable)的属性键名。
    var obj = {name:'秦司令',age:20};
    Object.keys(obj)  //["name","age"]
    

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

    var obj = {a:1,b:2,c:3};
    for(let key of Object.keys(obj)){
      console.log(key)  // a b c
    }
    for(let values of Object.values(obj)){
      console.log(values) // 1 2 3
    }
    for(let [k,v] of Object.entries(obj)){
      console.log([k,v]) // [name,'秦司令',age:20]  
    }
    
    Object.values()
    Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
    var obj = {name:'秦司令',age:20};
    Object.values(obj) // ["秦司令",20]
    

    返回数组的成员顺序

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

    上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b,c,d

    Object.values只返回自身可遍历属性

    var json = Object.create({},{p:{value:123}})
    Object.values(json)  //[]
    

    上面代码中,Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的,因为p的属性描述对象的enumerable默认是false,Object.values不会返回这个属性,只要把enumerable改成true,Object.values就返回这个属性p值

    var obj = Object.create({},{p:{
        value:2,
        enumerable:true 
    }})
    Object.values(obj)  //[2]
    

    Object.values会过滤属性名为Symbol值的属性

    Object.values({[Symbol()]:123,name:'秦司令'})
    // ['秦司令']
    

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

    Object.values('fooa')
    // ['f','0','0','a']
    

    上面代码中,字符串会先转换成一个类似数组的对象,字符串的每个字符,就是该对象的一个属性,因此,Object.values返回每个属性的键值,就是各个字符组成的一个数组

    如果参数不是对象,Object.values会先将其转换为对象。由于数值和布尔值的包装类对象,都不会为实例添加非继承的属性,所以,Object.valus会返回空数组

    Object.values(43) //[]
    Object.values(true) // []
    
    Object.entries()
    Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
    var obj = {foo:'bar',baz:43}
    Object.entries(obj)
    // [["foo","bar"],["baz",43]]
    

    如果原对象的属性名是一个Symbol值,该属性会被忽略

    Object.entries({[Symbol()]:123,foo:'abc'}) 
    //[["foo","abc"]]
    

    Object.entries的基本用途是遍历对象的属性

    let obj = {one:1,tow:2}
    for(let [k,v] of Object.entries(obj)){
      console.log(`${JSON.stringify(k)}:${JSON.stringify(v)}`)
    }
    // "one":1  
    // "tow":2
    

    Object.entries另一用处是将对象转换成Map结构

    var obj = {foo:'bar',name:'秦司令'}
    var map = new Map(Object.entries(obj))
    // Map{foo:'bar',name:'秦司令'}
    

    如有问题,望大神指点

    相关文章

      网友评论

          本文标题:Es6对象新方法

          本文链接:https://www.haomeiwen.com/subject/eladkqtx.html