new 一个对象,查看它原型的构造函数:
接下来一个一个说:
(1)Object.assign()——ES6
Object.assign()
方法用于对象的合并,将源对象(第一个参数)的所有可枚举属性,复制到目标对象(后面所有参数)。即将其他对象的属性复制到某个对象中
1 const obj = {a:1} 2 const obj01 = {b:2} 3 const obj02 = {c:3} 4 Object.assign(obj,obj01,obj02) 5 console.log(obj); // {a: 1, b: 2, c: 3}
注意:
- 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 如果只有一个参数,
Object.assign()
会直接返回该参数 - 由于
undefined
和null
无法转成对象,所以如果它们作为参数,就会报错。这两个不是出现在第一个目标对象时,处理规则有所不同。这些参数都会转成对象,如果无法转成对象,就会跳过。这意味着,如果undefined
和null
不在首参数,就不会报错。 - 其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
-
1 const v1 = 'abc'; 2 const v2 = true; 3 const v3 = 10; 4 5 const obj = Object.assign({}, v1, v2, v3); 6 console.log(obj); // { "0": "a", "1": "b", "2": "c" }
- 上面代码中,
v1
、v2
、v3
分别是字符串、布尔值和数值,结果只有字符串合入目标对象(以字符数组的形式),数值和布尔值都会被忽略。这是因为只有字符串的包装对象,会产生可枚举属性。 -
1 Object(true) // {[[PrimitiveValue]]: true} 2 Object(10) // {[[PrimitiveValue]]: 10} 3 Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
- 上面代码中,布尔值、数值、字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性[[PrimitiveValue]]上面,这个属性是不会被Object.assign()拷贝的,只有字符串的包装对象,会产生可枚举的实意义属性,那些属性则会被拷贝
-
Object.assign()
拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false
)。-
1 Object.assign({b: 'c'}, 2 Object.defineProperty({}, 'invisible', { 3 enumerable: false, 4 value: 'hello' 5 }) 6 ) 7 // { b: 'c' }
-
- 属性名为 Symbol 值的属性,也会被
Object.assign()
拷贝。
(2)Object.create()
用于在没有构造函数的情况下,也能创建子对象
语法:
const 子对象名 = Object.create(父对象)
create()创建出来的新对象的__proto__被自动设置为create()的参数,也就是自动继承了父对象了
1 const son = Object.create(father,{ 2 // 这里的格式与Object.defineProperties中格式一样 3 name: { 4 value: "张三", 5 writable:true, 6 enumerable:true, 7 configurable:true 8 }, 9 age:{ 10 value:26, 11 writable:true, 12 enumerable:true, 13 configurable:true 14 } 15 }) 16 17 console.log(son.type); // 人 18 console.log(son.name); // 张三 19 console.log(son.age); // 26
说明:
- create()第二个参数可选,不填就是创建一个空的子对象
(3)Object.defineProperty() & Object.defineproperties()
①Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
1 const obj ={} 2 Object.defineProperty(obj,'name',{ 3 value: '张三', 4 writable:true, 5 enumerable:true, 6 configurable:true 7 }) 8 console.log(obj); //{name: "张三"}
说明:
- value:定义的属性的值
- writable:属性是否可被修改
- enumerable:是否可被枚举(无法被for...in..获取到,但是可以直接访问)
- configurable:控制是否可以修改writable和enumerable 还有另外两个可选键值:get & set :可用于控制属性的修改时控制,vue双向绑定就是基于Object.defineproperty这个方法
-
1 const obj ={} 2 let val = "" 3 4 Object.defineProperty(obj,'name',{ 5 enumerable:true, 6 configurable:true, 7 get(){ 8 console.log("get:",val); 9 return val 10 }, 11 set(newVal){ 12 console.log("set:",newVal); 13 val=newVal 14 } 15 }) 16 17 val="赵四" 18 obj.name=val // set 19 console.log(obj.name); // get
②Object.defineproperties用于同时在对象上定义多个属性,用法与defineproperty类似
1 var obj = {}; 2 Object.defineProperties(obj, { 3 'property1': { 4 value: true, 5 writable: true 6 }, 7 'property2': { 8 value: 'Hello', 9 writable: false 10 } 11 // etc. etc. 12 });
(4)Object.entries()/Object.fromEntries() & Object.keys() & Object.values() —ES6
作用与数组的这三个同名办法相同,都是用来遍历对象的
①Object.entries()返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
1 const obj = { foo: 'bar', baz: 42 }; 2 Object.entries(obj)
②Object.fromEntries()是Object.entries的逆操作,用于将一个键值对数组转换为对象
1 let obj = Object.fromEntries([ 2 ['a', 1], ["b", 2] 3 ]) 4 console.log(obj); // {a: 1, b: 2}
该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。
③Object.keys()返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
1 var obj = { foo: 'bar', baz: 42 }; 2 Object.keys(obj) 3 // ["foo", "baz"]
④Object.values()回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
1 const obj = { foo: 'bar', baz: 42 }; 2 Object.values(obj) 3 // ["bar", 42]
(5)Object.preventExtensions() & Object.seal() & Object.freeze()
这三个属性都是用来控制对象的扩展
①Object.preventExtensions():禁止给对象添加新属性
const obj ={ name:"张三", age: 26 } Object.preventExtensions(obj) obj.sex = 1 console.log(obj); // {name: "张三", age: 26}
说明:
- 这里没有使用严格模式,所以默认是修改失败的。严格模式下会报错:Uncaught TypeError: Cannot add property sex, object is not extensible
原理:
每个对象内部有一个内部属性extensible = true。此方法就是将对象的内部属性extensible = false
②Object.seal():禁止添加新属性,禁止删除现有属性
1 const obj ={ 2 name:"张三", 3 age: 26 4 } 5 6 Object.seal(obj) 7 8 obj.sex = 1 9 console.log(obj); // {name: "张三", age: 26} 10 delete obj.age 11 console.log(obj); // {name: "张三", age: 26}
说明:
- 同样是在严格模式下会报错
原理:
- extensible = false
- configurable = false
③Object.freeze():禁止添加删除属性,不能修改任何属性值
1 const obj ={ 2 name:"张三", 3 age: 26 4 } 5 6 Object.freeze(obj) 7 8 obj.sex = 1 9 console.log(obj); // {name: "张三", age: 26} 10 delete obj.age 11 console.log(obj); // {name: "张三", age: 26} 12 obj.name = "李四" 13 console.log(obj); // {name: "张三", age: 26}
说明:
- 同样的,需要开启严格模式才会报错
原理:
- extensible = false
- configurable = false
- writable = false
(6)Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor()
方法返回指定对象上一个自由属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
1 const obj = { 2 name : "张三" 3 } 4 const desc = Object.getOwnPropertyDescriptor(obj,'name') 5 6 console.log(desc); // {value: "张三", writable: true, enumerable: true, configurable: true}
说明:
- 如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回
undefined
。 - 可以获取的属性有:
- writable
- enumerable
- configurable
- value
- get
- set
- get和set这两个访问器函数,只有在定义了才有,否则是undefined
注意:
- 在 ES5 中,如果该方法的第一个参数不是对象(而是原始类型),那么就会产生出现
TypeError
。而在 ES6,第一个的参数不是对象的话就会被强制转换为对象。
(7)Object.getOwnPropertyDescriptors()——ES6
Object.getOwnPropertyDescriptors()
方法,返回指定对象所有自身属性(非继承属性)的描述对象。
1 const obj = { 2 foo: 123, 3 get bar() { return 'abc' } 4 }; 5 6 Object.getOwnPropertyDescriptors(obj) 7 // { foo: 8 // { value: 123, 9 // writable: true, 10 // enumerable: true, 11 // configurable: true }, 12 // bar: 13 // { get: [Function: get bar], 14 // set: undefined, 15 // enumerable: true, 16 // configurable: true } }
上面代码中,Object.getOwnPropertyDescriptors()
方法返回一个对象,所有原对象的属性名都是该对象的属性名,对应的属性值就是该属性的描述对象。
该方法的引入目的,主要是为了解决Object.assign()
无法正确拷贝get
属性和set
属性的问题。
Object.getOwnPropertyDescriptors()
方法的另一个用处,是配合Object.create()
方法,将对象属性克隆到一个新对象。这属于浅拷贝。
1 const obj = {name:"张三"} 2 const clone = Object.create(Object.getPrototypeOf(obj),Object.getOwnPropertyDescriptors(obj)) 3 4 console.log(obj === clone); // false
说明:
- getPrototypeOf()方法返回指定对象的原型
- Object.getOwnPropertyDescriptors(obj)相当于直接获取自身属性当作第二个参数
- 另外,Object.getOwnPropertyDescriptors()
方法可以实现一个对象继承另一个对象。以前,继承另一个对象,常常写成下面这样。
1 const obj = { 2 __proto__: prot, 3 foo: 123, 4 };
ES6 规定__proto__
只有浏览器要部署,其他环境不用部署。如果去除__proto__
,上面代码就要改成下面这样。
1 const obj = Object.create(prot); 2 obj.foo = 123; 3 4 // 或者 5 6 const obj = Object.assign( 7 Object.create(prot), 8 { 9 foo: 123, 10 } 11 );
有了Object.getOwnPropertyDescriptors()
,我们就有了另一种写法。
1 const obj = Object.create( 2 prot, 3 Object.getOwnPropertyDescriptors({ 4 foo: 123, 5 }) 6 );
(8)Object.getOwnPropertyNames()
Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
Object.getOwnPropertyName()返回一个数组,该数组对元素是obj自身拥有的枚举或不可枚举属性名称字符串。数组中枚举属性的顺序与通过for...in...循环(或Oject.keys)迭代对象属性时一致。
1 var arr = ["a", "b", "c"]; 2 console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"] 3 4 // 类数组对象 5 var obj = { 0: "a", 1: "b", 2: "c"}; 6 console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"] 7 8 // 使用Array.forEach输出属性名和属性值 9 Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) { 10 console.log(val + " -> " + obj[val]); 11 }); 12 // 输出 13 // 0 -> a 14 // 1 -> b 15 // 2 -> c 16 17 //不可枚举属性 18 var my_obj = Object.create({}, { 19 getFoo: { 20 value: function() { return this.foo; }, 21 enumerable: false 22 } 23 }); 24 my_obj.foo = 1; 25 26 console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]
如果你只要获取到可枚举属性,可以使用Object.keys
或用for...in
循环(还会获取到原型链上的可枚举属性,不过可以使用hasOwnProperty()
方法过滤掉)。