从零开始学_JavaScript_系列(39)——对象的扩展(2)Object对象的扩展方法
2017-06-04 19:26
597 查看
对象的扩展
0、一句话总结
属性名,以及是属性的函数的简洁写法,写起来简单易阅读属性名可以用变量字符串拼接起来(话说以前也有吧?)
函数都有name属性,但set和get也要加前缀
Object.is判断两个变量是否相等
Object.assign可以合并对象的非原型链上,且可枚举属性
Object.getOwnPropertyDescriptor查看属性是否可枚举、可修改、可赋值
Object.keys获取对象非原型链上,且可枚举属性的key
Object.values获取对象非原型链上,且可枚举属性的值
Object.entries同时获取上面两个
当属性在原型链上,或者不可枚举时,会被很多方法忽视(参照6.1)
__proto__和prototype的关系(参照7.1)
Object.setPrototypeOf(obj, prototype)设置__proto__属性
Object.getPrototypeOf(obj)获取__proto__属性
es7新增对对象有效的扩展运算符…(三个点)
本篇没有的请翻看【对象的扩展】系列的其他篇
4、Object的扩展
4.1、判断两个变量是否相等(Object.is)
Object.is(value1, value2);简单的说,判断2个值是否相等,相等返回true,不等返回false。
类似===,但与其在某些表现略有差异,如代码:
Object.is(+0, -0); //false +0 === -0; //true Object.is(NaN, NaN); //true NaN === NaN; //false
另外需要在注意的是,按引用传递类型,比如{}或者[],哪怕看起来都是空数组、空对象,但2个不同的变量作为参数时,他们是不相等的。
(我似乎提升
4.2、将对象的属性合并到另外一个对象之中(Object.assign)
4.2.1、定义
Object.assign(target, …sources)简单来说,就是将参数2,3,4……里面的对象的所有 可枚举 属性,添加到参数1这个对象之中。
返回值是参数1这个对象(但因为对象是按引用传递,所以返回值和参数1是一样的);
需要注意的是,被添加对象的属性的数据类型,如果是按引用传递,那么该属性将以按引用传递的形式添加到第一个参数之中。
var foo = { a: "1" } var child = { name: "child" } var bar = { child, b: "2" } var target = { name: "target" } var result = Object.assign(target, foo, bar); console.log(target); //Object {name: "target", a: "1", child: Object, b: "2"} console.log(target.child === child); //true console.log(result === target); //true
4.2.2、属性覆盖:
同名属性,参数位置靠后者覆盖靠前者。var foo = { name: "1" } var target = { name: "target" } Object.assign(target, foo); console.log(target.name); //"1"
4.2.3、必须可枚举
可枚举,具体来说,就是该属性enumerable值为false时,如代码var foo = Object.defineProperty({}, "name", { value: "foo", enumerable: false }) console.log(foo.name); //"foo" var target = { name: "target" } Object.assign(target, foo); console.log(target.name); //"target"
注意:
通过 Object.defineProperty 方法添加新属性,未设置的属性名,不然上面里不包含writable和configurable,其默认值为false
4.2.4、参数一必须是对象或者可以转为对象
参数一如果不是对象,那么至少要能转为对象,例如:var num = Object.assign(1); console.log(num); //Number {[[PrimitiveValue]]: 1} //作为对比 new Number(1); //Number {[[PrimitiveValue]]: 1}
说明num是一个Number类型的对象。他可以像number一样进行正常的数学运算;
也可以像一个对象一样添加属性,只要不对它进行赋值,那么就会一直保持是对象状态。
如代码:
var num = Object.assign(1); typeof num; //"object" Object.assign(num, {name: "obj"}); num.name; //"obj" num + 10; //11 Object.prototype.toString.call(num); //"[object Number]"
类似可以推导到Boolean类型、String类型等基本类型,甚至可以对正则表达式使用,如代码:
var reg = Object.assign(/\d/, {name: "reg"}) reg; // /\d/ reg.name; //"reg"
但,基本类型里,
null和
undefined不行。
另外,参数一也不能是函数,不管是声明的还是变量赋值的都不行,除非通过new生成该函数的实例。
var test = function () { } var res = Object.assign(test, {name: "fun"}); //Uncaught TypeError: Cannot assign to read only property 'name' of function 'function () {}'
4.2.5、其他参数会隐式转换为对象,并且将可枚举属性添加进去
之前提过,只有 可枚举 的属性可以添加,因此假如其他参数是number或者boolean显然是不行的,即使被转换为对象,也无法添加。因此,基本类型里只有string有意义,例如”string”转为对象后,key为”0”时,值为”s”。
而扩展类型里,Array也是有意义的,他的下标就是key,并且该key可以被枚举。
4.2.6、再次提示,这种拷贝方法是浅拷贝
如果只是要合并属性是可以用的,但注意是浅拷贝,也就是数据类型为按引用传递类型时,只拷贝引用,而不是创建一个新的。如果有深拷贝的需求,请自行寻找办法。
另外,因为这种方式是浅拷贝,所以不会递归执行,
因此也不必担心参数2和参数3有同名属性且该属性是按引用传递,参数3覆盖参数2在参数1的属性时,导致参数2这个对象的属性的值受到影响。
具体来说,其实质就是:
//a,b,c都有属性name,且name是不同的对象 Object.assign(a,b,c); a.name = b.name; a.name = c.name; //结果是a.name = c.name,但b.name的值因为不是递归,所以自身不受影响。
4.2.7、对setter和getter不会正确生效
简单来说,set和get复制过来后,复制的仅是值,而不包括setter和getter的函数。如代码:let foo = { _val: 0, get val() { return this._val + 1; }, set val(val) { this._val = val; } } var bar = Object.assign({}, foo); foo; //{_val: 0} bar; //{_val: 0, val: 1} foo.val = 1; foo.val; //2 bar.val = 1; bar.val; //1
注意看以上,从foo通过assign将属性合并到bar后,val属性变成一个普通变量了。
对val属性的赋值和获取,也没有正确生效。
解决办法:
通过
Object.getOwnPropertyDescriptors(obj)(参照4.3)和
Object.defineProperties()两个方法完成获取和定义。
如代码:
let foo = { _val: 0, get val() { return this._val + 1; }, set val(val) { this._val = val; } } var getAttributes = Object.getOwnPropertyDescriptors(foo); console.log(getAttributes); //这个自行查看吧,跟defineProperties的参数2是相同的,显示configurable、setter等属性 let bar = Object.defineProperties({}, getAttributes); bar; //{_val: 0} bar.val = 1; bar.val; //2
4.3、查看是否可枚举、可修改、可赋值(Object.getOwnPropertyDescriptor)
Object.getOwnPropertyDescriptor(obj, prop)Object.getOwnPropertyDescriptors(obj) //需要es7,IE11不支持
获取enumberable、configurable和writable属性,以及value,和通过Object.defineProperty设置其的行为类似。
第一个获取指定属性的,第二个获取所有属性的,就像设置他们一样的形式来获取;
let foo = { name: "foo", test: "test" } Object.defineProperty(foo, "name", { enumerable: false }); let one = Object.getOwnPropertyDescriptor(foo, "name"); console.log(one); //{value: "foo", writable: true, enumerable: false, configurable: true} let all = Object.getOwnPropertyDescriptors(foo); console.log(all); //Object {name: Object, test: Object} //name和test也是对象,对象的属性参考上面的one
4.4、获取对象所有key(Object.keys)
Object.keys(obj)获取obj对象,非原型链上,enumberable的值为true的所有属性的key,依次放到数组中并返回该数组。
var obj = Object.create({a: "A"}, { b: { value: "B", enumerable: true } }); console.log(Object.keys(obj)); //["b"] console.log(Object.values(obj)); //["B"]
4.5、获取对象所有值(Object.values)
Object.values(obj)按照MDN说法,这个是实验性的,IE不兼容。但是我实测结果,IE11开IE9的文档模式,这个方法是可以正常执行的。
效果是获取obj对象,非原型链上,enumberable的值为true的所有属性的values。同样依次放到一个数组中并返回该数组。
代码参照4.4
4.6、同时获取对象的所有key和value(Object.entries)
Object.entries(obj)兼容性不好,IE11才能跑,10都不行。
也是只对非原型链,以及enumerable值为true的才有效。
返回一个数组,数组的每个元素是一个key+val组合。
返回数组的每个元素也是一个数组,下标为0的地方为key,下标为1的为value。
如代码:
var obj = Object.create({a: "A"}, { b: { value: "B", enumerable: true }, c: { value: "C", enumerable: true } }); console.log(Object.entries(obj)); //[["b", "B"], ["c", "C"]]
5.属性的可枚举性
5.1、如何设置可枚举性
Object.defineProperty(obj, prop, descriptor)Object.defineProperties(obj, props)
第一个设置单个属性的,第二个可以同时设置多个属性。
通过设置属性的enumerable属性来设置其是否可枚举,true可枚举,false不可枚举。
在未锁定前可以设置,锁定后不可修改(并且会报错)
var foo = { name: "foo" } Object.defineProperty(foo, "name", { configurable: false }); var res = Object.getOwnPropertyDescriptor(foo, "name"); console.log(res); //Object {value: "foo", writable: true, enumerable: true, configurable: false} Object.defineProperty(foo, "name", { enumerable: false }); //Uncaught TypeError: Cannot redefine property: name
5.2、查看是否可枚举(以及其他)
参照4.3中的:Object.getOwnPropertyDescriptor(obj, prop)
Object.getOwnPropertyDescriptors(obj) //需要es7,IE11不支持
5.3、当可枚举属性为false时,被忽视的情况
for in遍历对象属性;
Object.keys()获取所有key
JSON.stringify()JSON序列化
原因是以上都会去遍历对象的key,然后根据key来获取值,如果不能枚举显然不能遍历咯。
var foo = Object.defineProperty({test: "test"}, "name", { value: "foo", enumerable: false, writable: true, configurable: true }) for (var i in foo) { console.log(i); } //test console.log(Object.keys(foo)); //["test"] console.log(JSON.stringify(foo)); //{"test":"test"}
相关文章推荐
- 从零开始学_JavaScript_系列(15)——js系列<4>(数值、字符串、对象、数组、函数、日期的基本方法)
- 从零开始学_JavaScript_系列(41)——对象的扩展(4)扩展运算符三个点...
- 从零开始学_JavaScript_系列(40)——对象的扩展(3)当枚举、原型链遇见对属性的操作
- 从零开始学_JavaScript_系列(40)——对象的扩展(3)当枚举、原型链遇见对属性的操作
- 从零开始学_JavaScript_系列(38)——对象的扩展(1)属性的简洁写法
- Javascript 日期对象Date扩展方法
- javascript继承学习系列之三:对象伪装(Object Masquerading)
- JavaScript String 对象扩展方法
- Javascript对象扩展 - Object
- javascript:利用Object.create()方法创建对象
- Sharepoint学习笔记—ECMAScript对象模型系列-- 3、如何查看SP object的所有方法(method)
- 给 Javascript 的 日期(Date)对象扩展一个格式化(format)方法
- Javascript 给String对象扩展HTML编码和解码的方法
- 【Object类型】JavaScript中的原生对象以及Microsoft AJAX Library中的相关扩展
- SharePoint【ECMAScript对象模型系列】-- 03. 如何查看SP object的所有方法(method)
- C# 3.0新特性之Automatic Properties(自动属性)、Object Initializers(对象初始化器)、Collection Initializers(集合初始化器)和Extension Methods(扩展方法)
- javascript的window.ActiveXObject对象,区别浏览器的方法
- javascript的window.ActiveXObject对象,区别浏览器的方法
- JavaScript String 对象扩展方法
- VS 2008 + .NET 3.5 - C# 3.0新特性之Automatic Properties(自动属性)、Object Initializers(对象初始化器)、Collection Initializers(集合初始化器)和Extension Methods(扩展方法)