登录

没有账号?快速注册
合作账号登录

文章资讯 News每一个设计作品都举世无双

当前位置:主页 > 文章资讯 > 专业问答 > Es6对象新方法

Es6对象新方法

日期:2018-12-20 / 人气:91    分享到:

该方法可以冻结一个对象,冻结对象指的是不能向这个对象,添加属性、删除属性、修改属性、以及不能修改该对象已有属性的可枚举型、可写性、可配置性,该方法返回被冻结的对象。


演示:


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:'秦司令'}





作者:秦司令


链接:https://www.jianshu.com/p/27d7f1563a4e


來源:简书


简书著作权归作者所有,任何形式的转载都请联系作者获得授权


编辑:墨阁网络工作室