JS对象
查看更多学习笔记:GitHub:LoveEmiliaForever
MDN中文官网
JS对象基础
对象基础操作
对象是一个包含相关数据和方法的集合
- 变量 --> 对象属性
- 函数 --> 对象方法
使用字面量定义JS对象(直接手动定义一个对象)
const person = {
name: 'Kim',
age: 24,
eat (food) {
console.log(`${this.name} eat some ${this.food}`)
}
}
点表示法
使用点表示法访问对象属性或方法,就像是JAVA或者Python中的面向对象一样
通过借助命名空间
这样还可以避免命名污染
(名字一样导致的冲突)
const person = {
name: {
firstName: 'Kim',
secondName: 'xiu'
}
}
// person就是命名空间,这样就不会有不同对象的同名方法使用冲突的问题
// 点表示法就是像如下一样访问属性或方法
person.name.firstName
person.name.secondName
括号表示法
用括号表示法访问属性,像是使用Python的字典类型一样,或者说是像用键值对一样
它的好处是支持将动态变量解析为属性名
,这样就可以通过变量动态访问对象属性
const person = {
name: 'Kim',
age: 24
}
for (item in ['name', 'age']) {
console.log(person[item])
}
// 最终输出
// Kim
// 24
设置、更新对象成员
直接给相关对象成员赋值,那么新值会覆盖旧值,就完成了对象成员更新
如果赋值时,相关对象成员不存在,那么就会新建相关对象成员
const person = {
name: 'Kim',
age: 24
}
// 更新属性值
person.name = 'Tim'
person.age = 24
// 新添加属性
person.tall = 170
person.walk = function () {
console.log(`${this.name} is walk`)
}
this的指向
this的指向有很多不同的情况,但是在对象方法内,this通常指向调用该方法的对象
这样的好处是,不同对象实例调用同一个方法时,方法内部的变量指向不会出现错误
// 下面的两个对象分别使用 introduceSelf() 方法,却不会调用到错误的 name 属性
const person1 = {
name: "Chris",
introduceSelf() {
console.log(`你好!我是 ${this.name}。`);
},
};
const person2 = {
name: "Deepti",
introduceSelf() {
console.log(`你好!我是 ${this.name}。`);
},
};
person1.introduceSelf() // 调用的是person1.name
person2.introduceSelf() // 调用的是person2.name
构造函数
用字面量定义对象只适合构建少数对象的情况
使用构造函数
可以将重复的工作简化
// 构造函数的首字母应该大写
function Person(name) {
this.name = name;
this.introduceSelf = function () {
console.log(`你好!我是 ${this.name}。`);
};
}
const salva = new Person("Salva");
salva.name;
salva.introduceSelf();
// "你好!我是 Salva。"
const frankie = new Person("Frankie");
frankie.name;
frankie.introduceSelf();
// "你好!我是 Frankie。"
对象原型
原型是 JavaScript 对象相互继承特性的机制
原型链
JavaScript 中所有的对象都有一个内置属性,称为它的 prototype
(原型)。原型本身也是一个对象,故原型对象也会有它自己的原型,逐渐构成了原型链
。原型链终止于拥有 null 作为其原型的对象上
当你试图访问一个对象的属性或方法时:如果在对象本身中找不到该属性,就会在原型中搜索该属性。如果仍然找不到该属性,那么就搜索原型的原型,以此类推,直到找到该属性,或者到达链的末端,在这种情况下,返回 undefined
-
访问对象原型的标准方法是
Object.getPrototypeOf(要获取原型的对象)
-
实际上,所有浏览器都是使用
要获取原型的对象.__proto__
获取原型对象
属性遮蔽
由于原型链中查找属性和方法是从初始对象一路沿着原型链查找的
因此,原型链中同名方法或属性,只会返回最开始出现的该属性或方法
也就是子类重写父类的方法或属性
设置原型
Object.create(指定的原型对象)
方法- 创建一个新对象,并指定新对象的原型对象
- 它返回的是一个对象,这个对象已经被指定了原型对象
- 构造函数
- 构造函数的
prototype
指向构造函数原型 - 被创建的对象的
__proto__
也指向构造函数原型 - 构造函数原型的
constructor
指向构造函数
- 构造函数的
直接在对象中定义的属性,被称为自有属性
面向对象
面向对象是对现实世界的抽象表达,映射了现实世界的各种关系
- 系统抽象为许多对象的集合,每个对象代表了这个系统的特定方面
- 一个对象可以向其他部分的代码提供一个公共接口
- 其他部分不需要关心对象内部是如何完成任务的,保持了对象内部状态的私有性
类与实例
- 类
- 类并不做任何事情,类只是一种用于创建具体对象的模板
- 由类创建实例的过程是由构造函数所完成的
- 构造函数可根据给定的值初始化实例的内部状态
- 实例
- 是由类创建的具体的对象
- 每个实例都是不同的
// 伪代码表示
类 学生
属性
名字
年龄
方法
吃饭()
构造函数
学生(名字, 年龄)
// 小红和小李分别是学生类的不同实例
小红 = new 学生("小红", 24)
小李 = new 学生("小李", 20)
继承
继承,用来表示类之间的关系
可以让子类继承父类的属性和方法,这样就节省精力
// 伪代码表示
类 人类
属性
名字
年龄
方法
吃饭()
构造函数
人类(名字,年龄)
// 学术类继承自人类类
// 因此,学生实例都有名字和年龄属性
类 学生 继承 人类
属性
方法
吃饭()
构造函数
学生(名字, 年龄)
- 在上面的例子中,人类类被称为
父类
或超类
,学生类被称为子类
或基类
- 学生类中同样也定义了
吃饭()
这个方法,这种行为叫做重写
- 而一个父类方法在不同子类中有不同实现,这种特性叫做
多态
封装
- 对象对外暴露了
接口
(通常是方法),这些接口可以完成一些操作 - 对象内部的属性、方法,可以设置为私有(外界无法访问),称之为
私有属性
、私有方法
- 对于对象外面,只能通过接口访问对象,因此保证了对象的
内部状态私有性
- 设置对象的接口、内部私有性、内部状态等,称为
封装
// 伪代码表示
类 学生
属性
名字
年龄
私有 喜欢的食物
方法
吃饭()
获取喜欢的食物(){返回 this.喜欢的食物}
构造函数
学生(名字, 年龄, 喜欢的食物)
上面的例子中,只有通过获取喜欢的食物()
,才能得到喜欢的食物
这一个私有属性
这就是对学术类进行了封装
JS的面向对象编程
这些关键字实际上是对背后实现面向对象功能代码的一个封装,也就是常说的语法糖
具体JS的面向对象编程是如何实现的,可以自行查找资料,推荐看看《JS高程4》
JS的类与构造函数
// 类定义
class Person {
// 属性定义
name;
// 构造函数定义
constructor(name) {
this.name = name;
}
// 方法定义
introduceSelf() {
console.log(`Hi! I'm ${this.name}`);
}
}
如果不写构造函数,那么JS会自动生成一个默认的构造函数
JS的继承
// 继承的定义
class Professor extends Person {
teaches;
constructor(name, teaches) {
// super()用于调用父类构造函数,它是必须的
super(name);
this.teaches = teaches;
}
// 重写方法introduceSelf()
introduceSelf() {
console.log(
`My name is ${this.name}, and I will be your ${this.teaches} professor.`,
);
}
grade(paper) {
const grade = Math.floor(Math.random() * (5 - 1) + 1);
console.log(grade);
}
}
JS的封装
class Student extends Person {
// 私有属性定义
#year;
constructor(name, year) {
super(name);
this.#year = year;
}
introduceSelf() {
console.log(`Hi! I'm ${this.name}, and I'm in year ${this.#year}.`);
}
// 封装的方法
canStudyArchery() {
return this.#year > 1;
}
}
- 私有属性定义,属性名前加一个
#
- 私有方法定义,属性名前加一个
#
JSON
JavaScript 对象表示法(JSON)是用于将结构化数据表示为 JavaScript 对象的标准格式,通常用于在网站上表示和传输数据(例如从服务器向客户端发送一些数据,因此可以将其显示在网页上)
JSON 可以作为一个对象或者字符串存在,前者用于解读 JSON 中的数据,后者用于通过网络传输 JSON 数据
- 将字符串转换为原生对象称为
反序列化
- 将原生对象转换为可以通过网络传输的字符串称为
序列化
如上所述,JSON 是一个字符串,其格式非常类似于 JavaScript 对象字面量的格式
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
}
]
}
- JSON 是一种纯数据格式,它只包含属性,没有方法。
- JSON 要求在字符串和属性名称周围使用双引号。单引号无效。
- JSON 实际上可以是任何可以有效包含在 JSON 中的数据类型的形式。
- 与 JavaScript 代码中对象属性可以不加引号不同,JSON 中只有带引号的字符串可以用作属性。