JS 常用对象方法总结
1.Object.create()
新建一个对象,新建对象拥有指定原型和若干个指定属性
接收两个对象参数:
proto:必选,新建对象的原型对象
propertiesObject:可选,给新建对象创建一些指定属性
用法:
const obj = {
name: 'jack',
printName: function() {
console.log(`my name is ${this.name}`)
}
}
obj.printName() // my name is jack
const test = Object.create(obj, {
'old': {value:17, writable: false, configurable: false, enumerable: false},
'type': {value:'hot girl', writable: true, configurable: true, enumerable: true},
})
test.name = 'rose'
test.printName() // my name is rose
console.log(test.old) // 17
console.log(test.type) // hot girl
Object.create的第一个参数是obj,作为新建对象test的原型,test继承obj的name、printName属性,其中printName是一个方法,所以test.name重新赋值,test.printName()输出了重新赋值后的语句
Objec.create的第二个参数也是对象,但对象内容是键值对,其中值还是一个对象,配置以下4个参数,参数描述此属性的行为
(1)value:属性指定的值
(2)enumerable:当且仅当该属性可被循环遍历时,为true
(3)writable:当且仅当该属性值可改变时,为true
(4)configurable:当且仅当该属性即可被更改,也可被删除时,为true
注:1.Object.create、Object.defineProperty、Objec.defineProperties 函数添加数据属性,writable、enumerable和configurable默认值为false。
2.使用对象直接创建的属性,writable、enumerable和configurable特性默认为true
以下测试writable,enumerable,configurable,紧接着上面代码举例:
// 测试enumerable属性
for (let i in test) {
console.log(i) // type name printName
}
以上代码遍历了test对象的属性,可看到只有3个属性输出,因为属性old的enumerable的值是false,使得old无法被遍历
// 测试writable属性
test.old = 18
console.log(test.old) // 17
test.type = 'bad girl'
console.log(test.type) // bad girl
以上代码分别修改了属性old和type,其中old的writable属性是false,说明old的值不能改变,所以test.old=18无效,输出仍然为17,而test.type能够正常输出改变后的值
// 测试configurable属性
console.log(test.type) // hot girl
delete test.type
console.log(test.type) // undefined
以上代码在删除type属性前正常输出,因为type的configurable是true,表示可删除,顾delete语句可删除type属性,重新输出后已找不到type属性,故输出undefined
2.Object.assign(target, source1, source2, ...., sourceN)
将源对象(source)的所有可枚举属性复制到目标对象上(target)
注:1.此方法只能复制源对象自身的属性(不复制继承属性),也不复制不可枚举的属性
2.如果复制时存在同名属性,则后面的属性值覆盖前面的属性值
3.此方法属于浅复制,而不是深复制,如果源对象某个属性的值是对象,那么目标对象复制得到的是这个对象的引用;由于此缘故,源对象的属性应该是简单的属性值,而不该指向另一个对象
举例:
const obj = {
name: 'jack',
printName: function() {
console.log(`my name is ${this.name}`)
},
url: {
host: 'hello.com',
port: 8080
}
}
let test = {}
Object.assign(test, obj)
test.printName() // my name is jack
console.log('url', test.url) // url { host: 'hello.com', port: 8080 }
以上代码成功通过Object.assign()将obj的属性拷贝到test上
以下分别对上面提出的注意点举例
(0) 只能复制源对象自身的属性,不复制继承属性
let objA = {
x: '1'
}
let objB = {
y: '2'
}
let objC = {
z: '3'
}
Object.setPrototypeOf(objB, objA) // 此方法在下文中提到,设置objA为objB的原型属性,objA继承属性x
Object.assign(objC, objB)
console.log(objC) // { z: '3', y: '2' }
以上代码中,objC最终没有输出属性x,因为objB中的属性x属于继承属性
(1) 不复制不可枚举的属性
let obj = {
name: 'jack'
}
Object.assign(obj, Object.defineProperty({}, 'old', {
value: '17',
enumerable: false
}))
console.log(obj) // { name: 'jack' }
Object.assign()的第二个参数返回一个对象,此对象包含一个不可遍历的属性old,从输出结果可看到并没有输出此属性,验证此方法不复制不可枚举的属性
(2) 如果复制时存在同名属性,则后面的属性值覆盖前面的属性值
let obj = {
name: 'jack'
}
Object.assign(obj, {
name: 'rose'
})
console.log(obj) // { name: 'rose' }
以上代码中,源对象的name属性覆盖了obj中的name属性
(3) 此方法属于浅复制,而不是深复制,如果源对象某个属性的值是对象,那么目标对象复制得到的是这个对象的引用
let target = {}
let source = {
info: {
name: 'jack'
}
}
Object.assign(target, source)
console.log(target) // { info: { name: 'jack' } }
source.info.name = 'rose'
console.log(target) // { info: { name: 'rose' } }
以上代码中,当更改source中的对象的属性时,target的对象的相应属性随之改变,可以看出目标对象拷贝的是源对象的引用,即它们指向同一个对象
(4) 由于Object.assign()实现的是浅复制,源对象的属性应该是简单的属性值,而不该指向另一个对象
let target = {
info: {
name: 'jack',
old: '17'
}
}
let source = {
info: {
name: 'rose'
}
}
Object.assign(target, source)
console.log(target) // { info: { name: 'rose' } }
从以上代码可看出,通常情况下,我们期望source中的info的name属性值覆盖掉target的info的name属性值。从结果上看,确实做到了这一点,但是把old属性覆盖掉了,我们通常不希望这样的事情发生,也反向证明此方法无法进行深拷贝
3.Object.is()
比较两个值是否严格相等,与严格相等运算符(===)的行为基本一致
在JS中比较两个值是否相等有相等符号(==)和严格相等符号(===),这两个符号都存在一定的缺陷,前者会自动转换数据类型,后者的NaN===NaN返回结果为false以及+0===-0返回true,这不符合我们的期待,Object.is()满足了这种条件,在所有环境中,当两个值是一样的,他们就相等
console.log(Object.is(+0, -0)) // false
console.log(Object.is(NaN, NaN)) // true
4.Object.getOwnPropertyDescriptors()
获取对象某个属性的描述对象
let obj = {
name: 'jack'
}
console.log(Object.getOwnPropertyDescriptor(obj, 'name'))
// { value: 'jack', writable: true, enumerable: true, configurable: true }
以上代码中,Object.getOwnPropertyDescriptor()方法返回一个对象,这个对象描述了属性name,分别是value,writable,enumerable,configurable具体含义上本有描述,此处不再重复
5.Object.defineProperty()
在对象上定义一个新属性,或修改原属性的行为
参数:
obj:必选,要定义属性的对象
prop: 必选,作用的属性名称
descriptor: 必选,要定义或修改的属性描述对象
let obj = {}
Object.defineProperty(obj, 'name', {
value: 'jack',
enumerable: true
})
console.log(obj) // { name: 'jack' }
以之相对还有一个Objec.defineProperties()方法,此方法能同时定义多个属性
let obj = {}
Object.defineProperties(obj, {
'name': {
value: 'jack',
enumerable: true
},
'old': {
value: 17,
enumerable: true
}
})
console.log(obj) //{ name: 'jack', old: 17 }
6~8为对象属性的遍历相关方法,不再一一举例,遍历对象还可用for...in,此循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
6.Object.getOwnPropertyNames()
返回一个数组,包括对象自身的所有属性(不含Symbol属性但包括不可枚举属性)
7.Object.getOwnPropertySymbols()
返回一个数组,包括对象自身的所有Symbol属性
8.Object.ownKeys()
返回一个数组,包含对象自身的所有属性,不管是否是Symbol,也不管是否可枚举
9.Object.setPrototypeOf()
设置一个对象的原型对象,返回对象本身
let proto = {}
let obj = {
type: 'hot girl'
}
Object.setPrototypeOf(obj, proto)
proto.name = 'rose'
proto.old = '17'
console.log(obj.name, obj.old) // rose 17
以上代码中,proto对象是obj的原型对象,所以通过设置proto的属性值,在obj中能够获取到
10.Object.getPrototypeOf()
用于读取一个对象的原型对象
class Obj {
}
let obj = new Obj()
console.log(Object.getPrototypeOf(obj) === Obj.prototype) // true
11.Object.keys()
返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的键名
12.Object.values()
返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的键值
13.Object.entries()
返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的键值对
11~13例子:
let obj = {
name: 'rose'
}
Object.defineProperties(obj, {
'old': {
value: '17',
enumerable: true
},
'type': {
value: 'hot girl',
enumerable: false
}
})
console.log(Object.keys(obj)) // [ 'name', 'old' ]
console.log(Object.values(obj)) // [ 'rose', '17' ]
console.log(Object.entries(obj)) // [ [ 'name', 'rose' ], [ 'old', '17' ] ]
以上代码中,除了属性name,分别定义了可枚举属性old和不可枚举属性type,输出即为定义所描述