JavaScript之Object操作

微信扫一扫,分享到朋友圈

JavaScript之Object操作

JavaScript之Object操作
一、对象的创建方式

  1. 字面量方式
    在ES6之后,对象字面量得到了扩展:

​ 能够在创建对象时设置原型;
​ 使用super关键字重写继承的属性方法;
​ 使用表达式来作为属性名;
​ 对象内的属性和方法也能够进行简写;

使用属性名表达式时不能进行简写

let object = {
a: 123,
inner:{
c:111
},
[‘b’+’bb’]: 321, // 属性名表达式
ccc, // 属性简写
test() { // 方法简写
console.log(‘this is a test’)
}, proto
:123, // 原型链
toString() { // 重写继承的方法
return “d ” + super.toString();
},
}
复制代码
2. 使用构造函数
Object构造函数会根据传入的参数来创建相应的对象:

如果给定值是 null 或 undefined,将会创建并返回一个空对象
如果传进去的是一个基本类型的值,则会构造其包装类型的对象
如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址

// 当不传参时,会返回一个空对象
let object = new Object() // 不传入参数时,括号可省略
object.name = ‘Xu’
object.age = 18
object.action = function() {
console.log(‘say hello’)
}

// 传入基本类型的值时
let a = new Object(‘abc’)
console.log(a) // String { “abc” }

// 传入引用类型的值时
let b = new Object(a)
console.log(b) // String { “abc” }
复制代码

使用字面量方式与构造函数方式的对比

字面量方式 构造函数方式 代码量少、清晰易读 通过接受参数,将对象实例的创建过程委托给另一个内置构造函数 强调对象为一个简单的可变的散列表,而不必一定派生自某个类 使用自定义构造函数创建对象,可以通过传参添加属性和方法,当需要定义的同类对象较多时,节省了定义对象的代码量,并且使对象属性和方法的结构更加清晰 对象字面量运行速度更快,因为不需要沿着作用域寻找Object()构造函数

  1. Object的create方法

  2. Object的assign方法

二、构造函数的方法

  1. create()

功能:使用指定的原型对象和属性创建一个新对象。
语法:Object.create(proto[, propertiesObject])
参数:

proto:新创建对象的原型对象;
propertiesObject:可选,如果没有指定为 undefined,则是要添加到新创建对象的不可枚举(默认) 属性(对象的属性描述符以及相应的属性名称,这些属性对应Object.defineProperties()的第二个数)。

返回:一个新对象,带着指定的原型对象和属性。

function Father() {
this.a = 123
}

Father.prototype.test = function() {
console.log(‘this is a test’)
}

let son1 = Object.create(Father.prototype) // 创建新对象son,其原型指向Father的原型对象
console.log(son1. proto
=== Father.prototype) // true

// 使用propertiesObject
let son2 = Object.create(Father.prototype, {
foo: {
writable: true,
value: 10
},
bar: {
set(value) {
console.log(value)
},
get() {
return 20
}
}
})

console.log(son2) //Father{bar:20, foo: 10}
console.log(son2. proto
=== Father.prototype) // true
复制代码
2. assign()

功能:将一个或多个源对象的所有可枚举属性的值复制到目标对象
语法:Object.assign(target, …sources)
参数:

target:目标对象
sources:源对象

返回:目标对象

当目标对象中的属性和方法的键名与源对象相同时,则会被覆盖。
该方法只会拷贝源对象自身可枚举的属性/方法到目标对象,且为浅拷贝。
调用该方法时会使用源对象的[[Get]]和目标对象的[[Set]],因此会调用相关的getter和setter。所以该方法不仅仅是单纯的复制或定义新的属性/方法,还有分配属性/方法。当合并源包含getter时,不适合将新属性合并到原型之中。
// 1.复制对象
let obj = {
a: 1
}

let copyObj = Object.assign({}, obj)
console.log(copyObj) // { a:1 }

// 2.浅拷贝
function test() {
let obj1 = {
a: 0, // 基本数据类型
b: { // 引用数据类型
c: 0
}
}

let obj2 = Object.assign({}, obj1)
console.log(obj2) // { a: 0, b: { c: 0}}
// 改变a的值,将不会相互影响
obj1.a = 1
console.log(obj2) // { a: 0, b: { c: 0}}
obj2.a = 2
console.log(obj1) // { a: 1, b: { c: 0}}
// 改变b的值,将会相互影响
obj1.b.c = 1
console.log(obj1) // { a: 1, b: { c: 1}}
console.log(obj2) // { a: 2, b: { c: 1}}

}

// 3.合并对象
let newObj = Object.assign(obj, { b: 2 }, { c: 3 })
console.log(newObj) // {a:1,b:2,c:3}
console.log(newObj === obj) // true

// 4.合并具有相同属性的对象
Object.assign(newObj, { b: 22 }, { c: 33 })
console.log(newObj) // {a: 1, b: 22, c: 33}

// 5.继承的属性与不可枚举的属性是不能拷贝的
let o = Object.create({ foo: 1 }, { // foo为原型上的属性
test1: { // 不可枚举的属性
value: 1,
enumerable: false
},
test2: { // 可枚举的属性
value: 2,
enumerable: true
}
})

Object.assign(obj, o)
console.log(obj) // {a: 1, b: 22, c: 33, test2: 2}

// 6.原始类型会被包装成对象
let str = ‘abc’
let boolean = true
let num = 123
let symbol = Symbol(“hhh”)

// 原始类型会被包装成对象,null、undefined会被忽略,且只有字符串的包装对象才有自身可枚举属性
let object = Object.assign({}, str, boolean, num, symbol, null, undefined)
console.log(object) // {0: “a”, 1: “b”, 2: “c”}
复制代码
3. defineProperty()

功能:在对象上定义一个新属性,或修改对象上现有的属性,并返回该对象
语法:Object.defineProperty(obj, prop, descriptor)
参数:

obj:要定义属性的对象
prop:要定义或修改的属性的名称或Symbol
descriptor:要定义或修改的属性的描述符

返回:进行定义/修改属性的对象

对象中的属性描述符主要分为两种:数据描述符和存储描述符,这两种描述符都是对象。一个描述符只能为两者其中之一,不能同时是两者。

数据描述符:是一个具有值的属性,该值可以是可写的,也可以是不可写的。
存储描述符:是由 getter 函数和 setter 函数所描述的属性。

数据描述符和存储描述符都拥有configurable、enumerable这两个键值;然后数据描述符特有value、writable这两个键值,存储描述符特有get、set这两个键值。
存储描述符是

数据描述符 存储描述符 configurable configurable enumerable enumerable value get writable set
描述符键值介绍:

configurable:属性的描述符是否可修改(同时该属性是否可被删除);默认为false。
enumerable:该属性是否为枚举属性;默认为false。
value:该属性对应的值;默认为undefined。
writable:该属性的值是否可修改;默认为false。
get:属性的getter函数,当访问该属性时便会调用该函数。执行时不传入任何参数,但会传入this对象,该函数的返回值会被用作属性的值;默认为undefined。
set:属性的setter函数,当属性值被修改时,会调用该函数。该方法接受一个参数(即赋予的新值),会传入赋值时的this对象;默认为undefined。

当使用点运算符或属性名表达式添加属性时,configurable、enumerable、writable都为true
// 数据描述符
obj = {}
Object.defineProperty(obj, ‘test1’, {
configurable: false, // 不可修改描述符
enumerable: false, // 不可枚举
value: 123,
writable: false // value不可修改
})

console.log(obj.test1) // 123
obj.test1 = 0 // 修改值
console.log(obj.test1) // 123,值没有被修改

// 存储描述符
let property = 321
Object.defineProperty(obj, ‘test2’, {
configurable: true,
enumerable: true,
get() {
return property
},
set(newVal) {
property = ++newVal
}
})

console.log(obj.test2) // 321
obj.test2 = 109 // 调用了set方法
console.log(obj.test2) // 110

// 修改属性描述符
Object.defineProperty(obj, ‘test1’, {
configurable: true
})
// can’t redefine non-configurable property “test1”

delete obj.test1
console.log(obj.test1) // 123

// 属性可枚举性
for (let item in obj) {
console.log(item) // test2
}
复制代码
4. defineProperties()

功能:在对象上定义一个或多个新属性,或修改对象上现有的属性,并返回该对象
语法:Object.defineProperties(obj, props)
参数:

obj:要定义属性的对象
props:要定义其可枚举属性或修改的属性描述符的对象

返回:进行定义/修改属性的对象

该方法props参数中的属性描述与defineProperty()中的相同
obj = {}
Object.defineProperties(obj, {
‘test1’: {
value: 123,
writable: true,
configurable: true
},
‘test2’: {
enumerable: true,
get() {
return 321
},
set(newValue) {
console.log(‘set new value’)
}
}
})

console.log(obj) // {test1: 123, test2: 123}
复制代码
5. getOwnPropertyDescriptor()

功能:查看对象上的自有属性对应的属性描述符
语法:Object.getOwnPropertyDescriptor(obj, prop)
参数:

obj:要查看的对象
prop:要查看的属性名

返回:如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回 undefined。

let descriptor = Object.getOwnPropertyDescriptor(obj, ‘test1’)
console.log(descriptor) // { value: 123, writable: true, enumerable: false, configurable: true }

descriptor = Object.getOwnPropertyDescriptor(obj, ‘test2’)
console.log(descriptor) // { get: get(), set: set(newValue), enumerable: true, configurable: false }

descriptor = Object.getOwnPropertyDescriptor(obj, ‘valueOf’)
console.log(descriptor) // undefined
复制代码
6. getOwnPropertyNames()

功能:返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
语法:Object.getOwnPropertyNames(obj)
参数:

obj:要查看的对象

返回:在给定对象上找到的自身属性对应的字符串数组

let symbolProperty = Symbol()
obj[symbolProperty] = ‘symbol’ // 以symbol为值的属性

let propertyNames = Object.getOwnPropertyNames(obj)
console.log(propertyNames) // [ “test1”, “test2” ],包含不可枚举的属性,但不包含以symbol为值的属性

// 数组对象
propertyNames = Object.getOwnPropertyNames([1, 2, 3])
console.log(propertyNames.sort()) // [ “0”, “1”, “2”, “length” ]
复制代码
7. getOwnPropertySymbols()

功能:返回一个给定对象自身的所有 Symbol 属性的数组。
语法:Object.getOwnPropertySymbols(obj)
参数:

obj:要查看的对象

返回:在给定对象自身上找到的所有 Symbol 属性的数组。

let symbol1 = Symbol(1),
symbol2 = Symbol(2)

obj[symbol1] = 123
obj[symbol2] = 321

let symbols = Object.getOwnPropertySymbols(obj)
console.log(symbols) // [ Symbol(), Symbol(1), Symbol(2) ]
复制代码
8. entries()

功能:返回一个由给定对象自身可枚举属性的键值对组成的数组。
语法:Object.entries(obj)
参数:

obj:要遍历的对象

返回:给定对象自身可枚举属性的键值对数组。

entries方法返回的数组,其排列的顺序与foo…in循环遍历时的顺序相同,区别在于foo-in循环还会枚举原型链中的属性。
obj.foo = ‘test2’
for (let item in obj) {
console.log(item) // test2、foo
}

let entries = Object.entries(obj)
console.log(entries) // [ [‘test2’, 321], [‘foo’,’test2′] ],只会返回可枚举的属性
复制代码
9. keys()

功能:返回一个由给定对象自身可枚举属性的键组成数组。
语法:Object.keys(obj)
参数:

obj:要遍历的对象

返回:一个表示给定对象的所有可枚举属性的字符串数组

let keys = Object.keys(obj)
console.log(keys) // [ “test2”, “foo” ]
复制代码
10. values()

功能:返回一个由给定对象自身可枚举属性的值组成的数组。
语法:Object.values(obj)
参数:

obj:要遍历的对象

返回:一个包含对象自身的所有可枚举属性值的数组。

let values = Object.values(obj)
console.log(values) // [ 321, “test2” ]
复制代码
11. getPrototypeOf()

功能:返回指定对象的原型[[proto]]
语法:Object.getPrototypeOf(obj)
参数:

obj:要返回原型的对象

返回:给定对象的原型。如果没有继承属性,则返回 null 。

obj = Object.create({ a: 1 })
let prototype = Object.getPrototypeOf(obj)

console.log(prototype) // { a: 1 }
console.log(prototype === {a:1}) // true
复制代码
12. setPrototypeOf()

功能:设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null
语法:Object.setPrototypeOf(obj, prototype)
参数:

obj:要设置原型的对象
prototype:原型对象

返回:设置完原型后的对象

由于JS引擎优化属性访问带来的特性的关系,更改对象的原型是一个很消耗性能的操作。所以尽量避免去设置更改一个对象的原型,而改成使用create()来创建拥有所需原型的新对象。
function A() {}
let b = new A()
console.log(b. proto
=== A.prototype) // true

let prototypeObj = {
a: 123
}
Object.setPrototypeOf(b, prototypeObj)
console.log(b. proto
=== A.prototype) // false
console.log(b. proto
=== prototypeObj) // true
复制代码
13. is()

功能:判断两个值是否为同一个值。
语法:Object.is(value_1,value_2)
参数:

value_1:被比较的第一个值
value_2:被比较的第二个值

返回:比较结果,布尔类型

判断规则:

都为undefined
都为null
都为true或false
都是相同长度的字符串且字符排序相同
是为同一个对象(同一个引用)
都为数字且
都为+0
都为-0
都为NaN
或都是非零而且非 NaN 且为同一个值

与==运算符的不同之处: == 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换, 而 Object.is不会强制转换两边的值。
与=== 运算符的不同之处: === 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等 ,而将Number.NaN与NaN视为不相等。
14. isExtensible()

功能:判断对象是否可拓展(添加新属性)
语法:Object.isExtensible(obj)
参数:

obj:要检测的对象

返回:是否可拓展的结果,布尔类型;

新对象默认是可拓展的。使用preventExtensions()、seal()、freeze()方法都可以标记一个对象为不可拓展
let newObj = { b: 123 }
let extensible = Object.isExtensible(newObj)
console.log(extensible) // true
Object.preventExtensions(newObj)

extensible = Object.isExtensible(newObj)
console.log(extensible) // false

newObj.a = 123 // error,不可新增属性
newObj.b = 321 // 可修改已有属性的值
Object.defineProperty(newObj,’b’,{enumerable:true}) // 可修改已有属性的描述符
delete newObj.b // 可删除已有属性
复制代码
15. isFrozen()

功能:判断对象是否被冻结(被冻结的对象不能被修改:不能添加新属性;已有的属性不能被删除,其值不能被该,其属性描述符不能被修改;其原型不能修改)
语法:Object.isFrozen(obj)
参数:

obj:要检测的对象

返回:是否被冻结的结果,布尔类型;

let newObj = { a: ‘a’ }
let frozen = Object.isFrozen(newObj)
console.log(frozen)// false,默认不被冻结
Object.freeze(newObj)
forzen = Object.isFrozen(newObj)
console.log(frozen) // true

newObj.b = ‘b’ // error,不可添加新属性
delete newObj.a // error,不可删除已有属性
Object.defineProperty(newObj, ‘a’, {
enumerable: false // error,不可修改已有属性的修饰符
})
newObj.a = 123 // error,不可修改已有属性的值

let extensible = Object.isExtensible(newObj)
console.log(extensible) // true,冻结对象同时也是不可拓展的对象
let sealed = Object.isSealed(newObj)
console.log(sealed) // true,冻结对象同时也是密封的对象
复制代码
16. isSealed()

功能:判断对象是否被密封(不可拓展,且属性都不可配置不可删除)
语法:Object.isSealed(obj)
参数:

obj:要遍历的对象

返回:是否被密封的结果,布尔类型;

let newObj = { a: ‘a’ }
let sealed = Object.isSealed(newObj)
console.log(sealed)// false,默认不被密封
Object.freeze(newObj)
sealed = Object.isSealed(newObj)
console.log(sealed) // true

newObj.b = ‘b’ // error,不可添加新属性
delete newObj.a // error,不可删除已有属性
Object.defineProperty(newObj, ‘a’, {
enumerable: false // error,不可修改已有属性的修饰符
})
newObj.a = 123 // 可修改已有属性的值

let extensible = Object.isExtensible(newObj)
console.log(extensible) // true,密封对象同时也是不可拓展的对象
复制代码
17. preventExtensions()

功能:将一个对象设置为不可拓展
语法:Object.preventExtensions(obj)
参数:

obj:要处理的对象

返回:已经不可拓展的对象

  1. freeze()

功能:将一个对象冻结
语法:Object.freeze(obj)
参数:

obj:要处理的对象

返回:被冻结的对象

  1. seal()

功能:将一个对象密封
语法:Object.seal(obj)
参数:

obj:要处理的对象

返回:被密封的对象

不可拓展、冻结、密封的对比:

不可拓展 冻结 密封 是否可新增属性 ✖ ✖ ✖ 是否可删除属性 ✔ ✖ ✖ 已有属性的描述符是否可修改 ✔ ✖ ✖ 已有属性的值是否可修改 ✔ ✖ ✔

不可拓展的空对象同时也是冻结和密封的
密封的对象同时是一个不可拓展的对象
冻结的对象也是一个密封对象,更是一个不可拓展的对象

三、实例化对象的方法

  1. hasOwnProperty()

功能:检测对象自身是否含有指定的属性
语法:obj.hasOwnProperty(prop)
参数:

prop:要检测的属性的 String 字符串形式表示的名称,或者 Symbol。

返回:判断结果;布尔类型

该方法与in运算符不同:该方法检测的是实例化对象本身所拥有的属性,而忽略从原型链继承的属性
function Parent() {
this.property = 123
}
Parent.prototype.a = 321 // 原型对象添加属性

let son123 = new Parent()
son123.test = 321

let res = son123.hasOwnProperty(‘test’)
console.log(res) // true
res = son123.hasOwnProperty(‘property’)
console.log(res) // true
res = son123.hasOwnProperty(‘a’)
console.log(res) // false,原型链上的属性
复制代码
2. propertyIsEnumerable()

功能:检测属性是否可枚举
语法:obj.propertyIsEnumerable(prop)
参数:

prop:要检测的属性名

返回:检测结果;布尔类型

let newObj = {
a: 123
}

Object.defineProperty(newObj, ‘b’, {
enumerable: false,
value: 321
})

let isEnumerable = newObj.propertyIsEnumerable(‘a’)
console.log(isEnumerable) // true
isEnumerable = newObj.propertyIsEnumerable(‘b’)
console.log(isEnumerable) // false
复制代码
3. isPrototypeOf()

功能:检测一个对象是否存在于一个对象的原型链上
语法:prototypeObj.isPrototypeOf(object)
参数:

object:在该对象的原型链上寻找

返回:查找结果;布尔类型

function Foo() {}
function Bar() {}
function Baz() {}

Bar.prototype = Object.create(Foo.prototype) // 使Foo为Bar的父类
Baz.prototype = Object.create(Bar.prototype) // 使Bar为Baz的父类
let baz = new Baz()

console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
复制代码
4. valueOf()

功能:返回指定对象的原始值
语法:obj.valueOf()
参数:无
返回:该对象的原始值

日常中,很少需要自己主动去调用该方法。当有需要时,javascript会自动调用它。
默认情况下,valueOf方法由Object后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf将返回对象本身。
javascript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不要类型的对象的valueOf方法的返回值和返回值类型可能存在不同。
不同类型对象的valueOf()方法返回值

对象 返回值 Array 数组对象本身 Boolean 布尔值 Date 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 时间戳 Function 函数本身 Number 数字值 Object 对象本身。默认情况 String 字符串值 Math和Error对象没有该方法
5. toString()

功能:返回一个表示该对象的字符串(经常被用来检测对象类型)
语法:obj.toString()
参数:无
返回:表示该对象的字符串

每个对象都拥有该方法,当该对象被表达为一个文本值时,或一个对象以预期的字符串方式引用时自然调用。
默认情况下,toString() 方法被每个 Object 对象继承。如果此方法未被重写,toString() 返回 [object type],其中 type 是对象的类型。因为该特性,因此经常被用来进行类型检测
// 1.方法改写
function Fruit() {
this.size = ‘big’
this.color = ‘red’
}

let orange = new Fruit()
console.log(orange.toString()) // [object Object]

Fruit.prototype.toString = function() {
return this animal is ${this.size} and ${this.color}
}
console.log(orange.toString()) // this animal is big and red

// 2.类型检测
let typeObj = []
console.log(Object.prototype.toString.call(typeObj)) // [object Array]

typeObj = ‘123’
console.log(Object.prototype.toString.call(typeObj)) // [object String]

typeObj = Symbol()
console.log(Object.prototype.toString.call(typeObj)) // [object Symbol]

console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(null)) // [object Null]
复制代码
6. toLocaleString()

功能:返回调用toString()的结果(被用于派生对象为了特定语言环境的目的而重载使用。)
语法:obj.toLocaleString()
参数:无
返回:表示对象的字符串

该函数提供给对象一个通用的toLocaleString 方法,即使不是全部都可以使用它。
Array、 Number、Date对该方法进行了重写

微信扫一扫,分享到朋友圈

JavaScript之Object操作

华为回应芯片被美国打压:所有行业都该清醒了 危、机并存

上一篇

腾讯会议发布企业版 最高支持2000人同时参会

下一篇

你也可能喜欢

JavaScript之Object操作

长按储存图像,分享给朋友