Object 重识(一)
内容有点儿多,将分为两篇内容与大家分享。有的地方确实难以理解,可以多动手实现一下,看看效果。
一直听说有这么一句话,在JavaScript中,一切皆为对象。
经本人慎重研究之后发现,此言的确不虚。(这不废话么,虚不虚的还用你说。)
今天斗胆跟大家一起讨论一下JavaScript
重的Object
。了解Object
背后的 -- 生活
阅读间隙,还得多注意休息哟~
1. 对象的创建
开始第一个小问题,看一下如何创建一个对象。创建对象有四(shi)种方式。以下几种方式都可创建一个对象,只不过创建之后的表现稍有不同。具体表现为原型和this
的指向问题。有兴趣的读者可点击查看相关文章。在这里我们就不详细介绍了。(偷个懒)
注意点:
四种方式创建对象,除了原型和this
指针表现不同,构造函数指向也有不同。(此时说明的是不手动指定构造函数的情况下)
- 字面量方式创建的对象。构造函数为
function Object() {}
- 构造函数创建。构造函数为函数本身
-
Object.create
创建的对象,构造函数为入参origin
的构造函数 -
class
方式创建,会将本身也作为构造函数。
1.1 字面量方式创建
const obj = {} // 构造函数为 [Function: Object]
1.2 构造函数创建
function Obj() {}
const obj = new Obj() // 构造函数为 [Function: origin]
1.3 Object.create 创建
const origin = {a: 1, b: 2}
const target = Object.create(origin) // 构造函数为 origin 的构造函数
1.4 class方式创建
class Origin {}
const target = new Origin() // 构造函数 [Function: Origin]
2. 属性和方法
注:
-
官方版
- 属性是这个对象的属性,方法是这个对象所拥有的功能
-
通俗版
- 属性是一个值,不可执行。
- 方法为一个函数,可执行。
2.1 属性和方法获取
1.获取确定的key
属性,使用 .
运算符 或 中括号
const obj = {
a: 1,
b: 2,
c: 3,
d: function () {}
}
obj.a === obj['a']// 1
obj.b === obj['b'] // 2
obj.c === obj['c'] // 3
obj.d === obj['d'] // function (){}
2.获取需要计算的kay
值,只能使用中括号方式
const obj = {
a1: 1,
a2: 2,
a3: 3,
a4: function (){}
}
for(let i = 1;i < 5;i ++) {
obj['a' + i]
}
// 1,2,3,function (){}
注意:
如果对象中不含有某个key
,获取到的为 undefined
例如:
const obj = {}
obj.c() // TypeError: obj.c is not a function
由于obj
中不含有c
这个方法,所以获取到的是undefined
。此值不是函数,执行报错
可修改为以下写法
const obj = {}
typeof obj.c === 'function' && obj.c()
这里有的读者可能会说这样也可以 obj.c && obj.c()
。这种写法在下面这种情况下依然会报错
const obj = {
c: 1
}
obj.c()
所以,还是要清楚的判断我们要获取的key
是一个函数,才能执行。
2.2 如何判断对象中含有某个值
在此段内容开始之前,先说一个小问题,如何判断对象中是否含有某个key
值?
1. 使用 2.1
中的属性获取
- 只需判断是否为
undefined
即可。 - 此方法有一个缺陷,如果此值确实为
undefined
,则会出现判断失误的情况
const obj = {
c: undefined
}
console.log(obj.c === 'undefined') // 判断为true,但是obj中确实含有c这个key
2. in
- 包含某个
key
// 包含某个key
function A () {
this.b = 1
}
const a = new A()
console.log('b' in a) // true
- 不包含某个
key
// 不包含某个key
function A () {
}
const a = new A()
console.log('b' in a) // false
- 查询的
key
,值为undefined
的情况
// 不包含某个key
function A () {
this.b = undefined
}
const a = new A()
console.log('b' in a) // true
- 查询的
key
存在于原型链上
function A () {
}
Object.prototype.b = 1
const a = new A()
console.log('b' in a) // true
注意点:
缺点:in
方法无法判断当前key
是存在于对象本身还是在原型链上。此情况,我们需要用到下面这种方法。
3. hasOwnProperty
查询属性是否存在于自身
- 存在于原型链上
function A () {}
Object.prototype.b = 1
const a = new A()
console.log(a.hasOwnProperty('b')) // false
- 存在于自身
function A () {
this.b = 1
}
const a = new A()
console.log(a.hasOwnProperty('b')) // true
- 属性值为
undefined
function A () {
this.b = undefined
}
const a = new A()
console.log(a.hasOwnProperty('b')) // true
总结:
- 属性获取不能判断属性值为
undefined
的情况 -
in
方法不能判断属性是在对象本身还是在原型链上 -
hasOwnProperty
可以判断属性是否存在于自身,同时也可判断属性值为undefined
的情况
2.3 删除对象的属性
删除对象的属性可以使用delete
方法,只不过此方法的性能并不算太优越
const obj = {
b: 1,
c: 2
}
delete obj.b
console.log(obj) // {c: 2}
休息会儿,这篇文章可长哈,循序渐进的来。
2.4 属性分类
JavaScript
中将属性分为两种:数据属性和访问器属性。
数据属性包括:Configurable
、Enumerable
、Writable
、Value
四个属性描述符
访问器属性包括:Configurable
、Enumerable
、Set
、Get
四个属性描述符
通过对比我们可以发现,属性描述有六类:
Configurable、Enumerable、Writeable、Value、Set、Get
注意:
修改描述符,只可以通过Object.defineProperty(obj, key, config)修改一个
|| Object.defineProperties(obj,config)修改多个
方法来修改。
例如:
const obj = {
a: 1,
b: 2,
c: 3
}
// 修改一个
Object.defineProperty(obj, 'a', {
enumerable: true,
writable: true,
configurable: true
})
// 修改多个
Object.defineProperties(person, {
a: {
enumerable: true,
writable: true,
configurable: true
},
b: {
enumerable: true,
writable: true,
configurable: true
}
}
1. 描述符介绍
Configurable
:是否可通过delete
删除属性、是否可重新定义属性、是否可修改描述符、是否可进行属性互换。
- 为
true
上述操作都可进行
const obj = {
a: 1,
b: 2,
c: 3
}
Object.defineProperty(obj, 'a', {
configurable: true
})
delete obj.a
Object.defineProperty(obj, 'a', {
value: 11
})
Object.defineProperty(obj, 'a', {
enumerable: true
})
Object.defineProperty(obj, 'a', {
set() {}
})
- 为
false
严格模式下报错,普通模式下过滤操作
const obj = {
a: 1,
b: 2,
c: 3
}
Object.defineProperty(obj, 'a', {
configurable: false
})
delete obj.a
Object.defineProperty(obj, 'a', {
value: 11
})
Object.defineProperty(obj, 'a', {
enumerable: true
})
Object.defineProperty(obj, 'a', {
set() {}
})
Enumerable
:是否可枚举
const obj = {
a: 1,
b: 2,
c: 3
}
// 为 true 的情况,可遍历
Object.defineProperty(obj, 'a', {
enumerable: true
})
for(let item in obj) {
console.log(item) // a, b, c 可遍历到 a
}
// 为false的情况,不可遍历
Object.defineProperty(obj, 'a', {
enumerable: false
})
for(let item in obj) {
console.log(item) // b, c 遍历不到 a
}
Writable
:是否可修改属性的值,加上它,将变为数据属性
const obj = {
a: 1,
b: 2,
c: 3
}
// 为 true 可修改属性值
Object.defineProperty(obj, 'a', {
writable: true
})
obj.a = 2
console.log(obj.a) // 2
// 为false 不可修改属性值 严格模式下会报错
Object.defineProperty(obj, 'a', {
writable: false
})
obj.a = 2
console.log(obj.a) // 1
Value
:属性的数据值,加上它,将变为数据属性
const obj = {
a: 1,
b: 2,
c: 3
}
Object.defineProperty(obj, 'a', {
value: 11
})
console.log(obj.a) // 11
Set
:写入属性时调用,加上它,将变为访问器属性
const obj = {
a: 1,
b: 2,
c: 3
}
Object.defineProperty(obj, 'a', {
set() {
console.log('a的值改变了')
}
})
obj.a = 2 // a的值改变了
Get
:读取属性时调用,加上它,将变为访问器属性
const obj = {
a: 1,
b: 2,
c: 3
}
Object.defineProperty(obj, 'a', {
get() {
console.log('获取a的值')
}
})
obj.a // 获取a的值
2. 属性互换:
数据属性 --> 访问器属性
将 Writable、Value
中的任意一个替换为 Set、Get
中的任意一个。
访问器属性 --> 数据属性
将 Set、Get
中的任意一个替换为 Writable、Value
中的任意一个。
示例可接着往下看
3. 获取某个属性的描述(查看此属性是数据属性还是访问器属性)
想要查看某个属性的描述,可以使用Object.getOwnPropertyDescriptor(obj, key)
来查看
const obj = {
a: 1
}
console.log(Object.getOwnPropertyDescriptor(obj, 'a'))
// { value: 1, writable: true, enumerable: true, configurable: true }
Object.defineProperty(obj, 'a', {
get() {
console.log('获取a的值')
}
})
console.log(Object.getOwnPropertyDescriptor(obj, 'a'))
/*
{
get: [Function: get],
set: undefined,
enumerable: true,
configurable: true
}
*/
此例我们可以验证 属性互换
的正确性,当我们将get
设置为 a
的描述符时,a
会变为访问器属性
接下文:Object 重识(二)