JS中的对象与继承

本节是阅读《高级程序设计(第四版)》的第八章 对象、类与面向对象编程 的总结以及自己的一些理解。

主要解决如下几个问题:

  1. 1-理解对象
  2. 2-理解对象创建过程
  3. 3-理解继承
  4. 4-理解类

1.理解对象

对象创建的形式一般是创建一个 Object 的实例,然后给它添加属性和方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// before
let animal = new Object()
animal.name = 'dog'
animal.age = 8
animal.leg = 4
animal.sayName = function () {
console.log(this.name)
}
// now
// 对象字面量形式声明
let animal = {
name: 'cat',
age: 2,
legs: 4,
sayName: function () {
console.log(this.name)
}
}

目录 :

  1. 1-1属性的类型
  2. 1-2定义多个属性
  3. 1-3读取属性的特征
  4. 1-4合并对象
  5. 1-5对象标识符及判定
  6. 1-6增强对象语法
  7. 1-7对象解构

1.1属性的类型

属性的类型分为两种:数据类型访问器类型

1.1.1数据类型

数据属性包含一个保存数据值的位置。值会从这个位置读取,也会写入到这个位置。数据库属性有4个特性描述它们的行为。

  1. configurable : 表示属性是否可通过 delete 删除并重新定义。
  2. enumerable : 表示属性是否可以通过 for-in 循环返回。
  3. writable : 表示属性的值是否可以被修改。
  4. value : 包含属性实际的值,默认为 undefined

如想修对象某一个属性的对应的特征,可用
Object.defineProperty()
去修改,如下:

1
2
3
4
5
6
7
8
9
10
11
let temp = {}
Object.defineProperty(temp, 'name', {
configurable: false,
enumerable: false,
writable: false,
value: 'xxx'
})
// 表示该对象的 name 属性的值为 'xxx' ,
// 同时,无法通过 delete 关键字去删除这个属性,
// 该属性无法枚举, 因此无法通过 for-in 或 Object.keys()得出,
// 该属性不可写, 因此无法设置 temp.name = 'yyy' , 该设置会无效。

1.1.2访问器类型

访问器不包含数据值。包含一个 getter 和一个 setter 函数。

  1. configurable : 同上。
  2. enumerable : 同上。
  3. get : 获取函数,读取属性时用,默认为 undefined
  4. set : 设置函数,设置属性时用,默认为 undefined

同样的,如想修对象某一个属性的对应的特征,可用 Object.defineProperty去修改,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let temp = {}
Object.defineProperty(temp, 'name', {
configurable: false,
enumerable: false,
get() {
return this._name
},
set(val) {
this._name = val
}
})
// 表示该对象的 name 属性的值为 'xxx' ,
// 同时,无法通过 delete 关键字去删除这个属性,
// 该属性无法枚举, 因此无法通过 for-in 或 Object.keys()得出,
// 该属性会通过 set 去劫持输入的值,并将输入的值 设置为对象自身的私有属性 _name
// 获取该值的时候,实际上是调用 get 函数,即获取的值实际上是对象自身的 _name 的值 而不是 name
// 这样的做法是避免直接使用者直接修改对应的值,从而达到私有属性的一个方法。

1.2定义多个属性

主要是调用 Object.defineProperties() 来配置多个属性的值。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let temp = {}
Object.defineProperties(temp, {
name: {
configurable: true,
enumerable: true,
get() {
return this._name
},
set(val) {
this._name = val
}
},
age: {
configurable: false,
enumerable: false,
writable: false,
value: 12
},
})

总结: 无论是 Object.defineProperties()Object.defineProperty() ,在对某一个值做配置时,要么使用访问器属性,要么对其 四个特征 进行配置,gettersetter
writablevalue不能同时存在一个对象描述上 的。

1.3读取属性的特征

主要是 Object.getOwnPropertyDescriptor() 的应用,该API可取得指定属性的属性描述符,接受两个参数,target 和 属性名。返回的是一个对象,对于访问器属性包含 configurableenumeranle以及gettersetter,如果是数据属性,则包含configurableenumerablewritablevalue,当为一个参数时返回 undefined

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let animal = {}
Object.defineProperties(animal, {
name: {
configurable: true,
enumrable: true,
writable: true,
value: 'cat'
},
legs: {
configurable: true,
enumrable: true,
set: function (v) {
this._legs = v
},
get: function () {
return this._legs
}
}
})

Object.getOwnPropertyDescriptor(animal, 'name')
Object.getOwnPropertyDescriptor(animal, 'legs'),结果如下:
avatar

1.4合并对象

主要是 Object.assign() 的应用,该API执行的是一个 潜复制,接受 两个 参数,一个为目标对象,一个为源对象。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 简单复制
let a = {}
let b = { c: 1 }
Object.assign(a, b)
console.log(a) // { c : 1 }
console.log(b) // { c : 1 }
console.log(a === b) // false 因为是浅复制,简单类型为2个不同对象

let c = { a: 1 }
let d = { b: { a: 1 } }
let temp = Object.assign(c, d)
console.log(c) // {a:1,b:{a:1}}
console.log(d) // {a:1,b:{a:1}}
d.b.a = 2
console.log(temp) // {a:1,b:{a:2}} 浅复制 所以temp值根据d的值也在变换,引用了同一个

1.5对象标识符及判定

Object.is()的应用,接受2个参数,返回Boolean,与全等判断( === ) 很相似。

例:

1
2
+0 === -0 // true
Object.is(+0, -0) // false

1.6增强对象语法

一些关于对象的语法糖。

1.6.1简写

当对象属性名与属性值相等时,可以简写。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let a = 'a'

// before
let obj1 = {
a: a
}

// 简写
let obj2 = {
a
}

console.log(obj1) // {a:'a'}
console.log(obj2) // {a:'a'}

1.6.2可计算变量

可以在对象字面量中完成动态属性赋值。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// before
const nameKey = 'name'
let person = {}
person[nameKey] = 'xxx'

console.log(person) // { name : 'xxx' }

// 可计算变量
let person2 = {
[nameKey]: 'xxx'
}

console.log(person2) // { name : 'xxx' }

// 更复杂的场景
const getKey = (key) => `${key}_dynamic`
let person3 = {
[getKey(nameKey)]: 'xxx'
}
console.log(person3) // { name_dynamic : 'xxx'}

1.6.3简写方法名

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// before
let person = {
name: 'xxx',
sayName: function () {
console.log(this.name)
}
}
person.sayName() // 'xxx'

// 简写
let person2 = {
name: 'xxx',
sayName() {
console.log(this.name)
}
}
person2.sayName() // 'xxx'

// 和可计算属性混用
const methodKey = 'sayName'
let person3 = {
name: 'xxx',
[methodKey]() {
console.log(this.name)
}
}
person3.sayName() // 'xxx'

1.7对象解构

个人认为对象解构,极大程度减少了代码中变量声明这块的代码量,使代码变得更简洁易懂。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
let animal = {
name: 'cat',
age: 2
}
// before
let name = animal.name
let age = animal.age

// 解构赋值
let { name, age } = animal

// 重命名的解构赋值
let { name1 = animal.name, age1 = animal.age } = animal

1.7.1嵌套解构

例:

1
2
3
4
5
6
7
8
9
10
11
let animal = {
name: 'cat',
age: 2,
group: {
belong: 'xxx'
}
}

// 一定要在外层有定义的情况下才能使用嵌套解构
let { group: belong } = animal
console.log(belong) // {belong:'xxx'}

1.7.2部分解构

例:

1
2
3
4
5
6
7
8
9
10
let animal = {
name: 'cat',
age: 2,
group: {
belong: 'xxx'
}
}

let { name } = person
console.log(age) // age is not define

2.理解对象创建过程

3.理解继承

4.理解类

__END__

o0Chivas0o
文章作者:o0Chivas0o
文章出处JS中的对象与继承
作者签名:Rich ? DoSomethingLike() : DoSomethingNeed()
版权声明:文章除特别声明外,均采用 BY-NC-SA 许可协议,转载请注明出处