文章目录
- 5-1. 新增的对象字面量语法
- 5-2. Object 的新增 API
- 5-4 类:构造函数的语法糖
- 传统的构造函数的问题
- 类的特点
- 5-5. 类的其他书写方式
5-1. 新增的对象字面量语法
- 成员速写
如果对象字面量初始化时,成员的名称来自于一个变量,并且和变量的名称相同,则可以进行简写
function createUser(loginId, loginPwd, nickName) {
const sayHello = function () {
console.log("loginId", this.loginId, "nickname", this.nickName);
};
return {
loginId,
loginPwd,
nickName,
sayHello,
id: Math.random(),
};
}
const u = createUser("abc", "123", "aaa");
- 方法速写
对象字面初始化时,方法可以省略冒号和 function 关键字
- 计算属性名
有的时候,初始化对象时,某些属性名可能来自于某个表达式的值,在 ES6,可以使用中括号来表示该属性名是通过计算得到的。
const prop1 = "name2";
const prop2 = "age2";
const prop3 = "sayHello2";
const user = {
[prop1]: "姬成",
[prop2]: 100,
[prop3]() {
console.log(this[prop1], this[prop2]);
},
};
user[prop3]();
console.log(user);
5-2. Object 的新增 API
- Object.is
用于判断两个数据是否相等,基本上跟严格相等(===)是一致的,除了以下两点:
- NaN 和 NaN 相等
- +0 和-0 不相等
- Object.assign
用于混合对象
- Object.getOwnPropertyNames 的枚举顺序
Object.getOwnPropertyNames 方法之前就存在,只不过,官方没有明确要求,对属性的顺序如何排序,如何排序,完全由浏览器厂商决定。
ES6 规定了该方法返回的数组的排序方式如下:
- 先排数字,并按照升序排序
- 再排其他,按照书写顺序排序
- Object.setPrototypeOf
该函数用于设置某个对象的隐式原型
比如: Object.setPrototypeOf(obj1, obj2),
相当于: ` obj1.__proto__ = obj2 `
5-4 类:构造函数的语法糖
传统的构造函数的问题
- 属性和原型方法定义分离,降低了可读性
- 原型成员可以被枚举
- 默认情况下,构造函数仍然可以被当作普通函数使用
// 构造函数 构造器
function Animal(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
// 定义实例方法(原型方法)
Animal.prototype.print = function () {
console.log(`【种类】:${this.type}`);
console.log(`【名字】:${this.name}`);
console.log(`【年龄】:${this.age}`);
console.log(`【性别】:${this.sex}`);
};
const a = new Animal("狗", "旺财", 3, "男");
a.print();
for (const prop in a) {
console.log(prop); //原型成员可以被枚举
}
// 类对照写法
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
print() {
console.log(`【种类】:${this.type}`);
console.log(`【名字】:${this.name}`);
console.log(`【年龄】:${this.age}`);
console.log(`【性别】:${this.sex}`);
}
}
类的特点
- 类声明不会被提升,与 let 和 const 一样,存在暂时性死区
- 类中的所有代码均在严格模式下执行
- 类的所有方法都是不可枚举的
- 类的所有方法都无法被当作构造函数使用
- 类的构造器必须使用 new 来调用
5-5. 类的其他书写方式
- 可计算的成员名
const printName = "print"; //可计算的成员名
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
//创建一个age属性,并给它加上getter,读取该属性时,会运行该函数
get age() {
return this._age + "岁";
}
//创建一个age属性,并给它加上setter,给该属性赋值时,会运行该函数
set age(age) {
if (typeof age !== "number") {
throw new TypeError("age property must be a number");
}
if (age < 0) {
age = 0;
} else if (age > 1000) {
age = 1000;
}
this._age = age;
}
[printName]() {
//可计算的成员名
console.log(`【种类】:${this.type}`);
console.log(`【名字】:${this.name}`);
console.log(`【年龄】:${this.age}`);
console.log(`【性别】:${this.sex}`);
}
}
var a = new Animal("狗", "旺财", 3, "男");
a[printName](); //可计算的成员名
Animal.abc = 123;
- getter 和 setter
Object.defineProperty 可定义某个对象成员属性的读取和设置
使用 getter 和 setter 控制的属性,不在原型上
- 静态成员
构造函数本身的成员
//静态成员与实例成员的区别
Animal.abc = 123;
const a = new Ainmal(“狗”, “旺财”, 3, “男”);
//abc 不能通过 a 来访问,只能通过构造函数的本身访问
//a 只能访问本的实例成员和原型的实例成员
使用 static 关键字定义的成员即静态成员
class Chess {
constructor(name) {
this.name = name;
}
static width = 50;
static height = 50;
static method() {}
}
//静态成员
console.dir(Chess);
Chess.method();
//实例成员
const chess = new Chess();
console.dir(chess);
- 字段初始化器(ES7)
注意:
1). 使用 static 的字段初始化器,添加的是静态成员
2). 没有使用 static 的字段初始化器,添加的成员位于对象上
3). 箭头函数在字段初始化器位置上,指向当前对象
-
类表达式
-
[扩展]装饰器(ES7)(Decorator)
横切关注点
装饰器的本质是一个函数
5-6. 类的继承
如果两个类 A 和 B,如果可以描述为:B 是 A,则,A 和 B 形成继承关系
如果 B 是 A,则:
B 继承自 A
A 派生 B
B 是 A 的子类
A 是 B 的父类
如果 A 是 B 的父类,则 B 会自动拥有 A 中的所有实例成员。
新的关键字:
extends:继承,用于类的定义
super
直接当作函数调用,表示父类构造函数
如果当作对象使用,则表示父类的原型
注意:ES6 要求,如果定义了 constructor,并且该类是子类,则必须在 constructor 的第一行手动调用父类的构造函数
如果子类不写 constructor,则会有默认的构造器,该构造器需要的参数和父类一致,并且自动调用父类构造器
【冷知识】
用 JS 制作抽象类
抽象类:一般是父类,不能通过该类创建对象
正常情况下,this 的指向,this 始终指向具体的类的对象