class
基本语法
通过构造函数生成实例对象
ES6 提供了更接近传统语言的写法
通过class
关键字,可以定义类,让对象原型的写法更加清晰、更像面向对象编程的语法
this
关键字则代表实例对象
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
类 — 可以看作是构造函数的另一种写法
class Point {
}
typeof Point
Point === Point.prototype.constructor
类的数据类型就是函数,类本身就指向构造函数
构造函数的prototype
属性,在 ES6 的“类”上面继续存在。类的所有方法都定义在类的prototype
属性上面
class Point {
constructor() {
}
toString() {
}
toValue() {
}
}
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
constructor方法
constructor
方法是类的默认方法,通过new
命令生成对象实例时,自动调用该方法。
一个类必须有constructor
方法,如果没有显式定义,一个空的constructor
方法会被默认添加。
定义了一个空的类Point
,自动为它添加一个空的constructor
方法
class Point {
}
// 等同于
class Point {
constructor() {}
}
constructor
方法默认返回实例对象(即this
),完全可以指定返回另外一个对象。
class Foo {
constructor() {
return Object.create(null);
}
}
new Foo() instanceof Foo
// false
上面代码中,constructor
函数返回一个全新的对象,结果导致实例对象不是Foo
类的实例。
类必须使用new
调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new
也可以执行。
class Foo {
constructor() {
return Object.create(null);
}
}
Foo()
// TypeError: Class constructor Foo cannot be invoked without 'new'
类的实例
1.使用new
命令生成类的实例 不加上new 会报错
2.实例的属性除非定义在this
对象上,否则都是定义在class
上
3.类的所有实例共享一个原型对象。
4.可以通过实例的__proto__
属性为“类”添加方法
取值函数(getter)和存值函数(setter)
1.“类”的内部可以使用get
和set
关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
2.存值函数和取值函数是设置在属性的 Descriptor 对象上的。
属性表达式
类的属性名,可以采用表达式。
let methodName = 'getArea';
class Square {
constructor(length) {
// ...
}
[methodName]() {
// ...
}
}
Class 表达式
类可以使用表达式的形式定义。
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
const MyClass = class { /* ... */ };
采用 Class 表达式,可以写出立即执行的 Class。
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('张三');
person.sayName(); // "张三"
person
是一个立即执行的类
重点
(1)严格模式
(2)不存在提升
(3)name 属性
(4)Generator 方法 --方法之前加上星号
(5)this 的指向 类的方法内部如果含有this
,它默认指向类的实例。单独使用该方法,可能报错。
静态方法
1.加上static
关键字,表示该方法不会被实例继承,直接通过类来调用
2.静态方法包含this
关键字,这个this
指的是类,而不是实例
3.父类的静态方法,可以被子类继承。
实例属性的新写法
实例属性除了定义在constructor()
方法里面的this
上面,也可以定义在类的最顶层。
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Getting the current value!');
return this._count;
}
increment() {
this._count++;
}
}
静态属性
指的是 Class 本身的属性,即Class.propName
,而不是定义在实例对象(this
)上的属性。
class继承
通过extends
关键字实现继承
class Point {
}
class ColorPoint extends Point {
}
不管有没有显式定义,任何一个子类都有constructor
方法。
class ColorPoint extends Point {
}
// 等同于
class ColorPoint extends Point {
constructor(...args) {
super(...args);
}
}
只有super
方法才能调用父类实例。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // ReferenceError
super(x, y);
this.color = color; // 正确
}
}
生成子类实例
let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true
Object.getPrototypeOf()
Object.getPrototypeOf
方法可以用来从子类上获取父类。
判断 一个类是否继承了另一个类
Object.getPrototypeOf(ColorPoint) === Point
// true
super
关键字
既可以当作函数使用,也可以当作对象使用
类的 prototype 属性和__proto__属性
对象都有__proto__
属性,指向对应的构造函数的prototype
属性。
class同时有prototype
属性和__proto__
属性,因此同时存在两条继承链。
(1)子类的__proto__
属性,表示构造函数的继承,总是指向父类。
(2)子类prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
上面代码中,子类B
的__proto__
属性指向父类A
,子类B
的prototype
属性的__proto__
属性指向父类A
的prototype
属性。
这样的结果是因为,类的继承是按照下面的模式实现的。
class A {
}
class B {
}
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);
const b = new B();
原生构造函数
是指语言内置的构造函数,通常用来生成数据结构
原生构造函数:
- Boolean()
- Number()
- String()
- Array()
- Date()
- Function()
- RegExp()
- Error()
- Object()
Mixin 模式的实现
Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口
const a = {
a: 'a'
};
const b = {
b: 'b'
};
const c = {...a, ...b}; // {a: 'a', b: 'b'}
mix
函数,可以将多个对象合成为一个类
使用的时候,只要继承这个类即可。
class DistributedEdit extends mix(Loggable, Serializable) {
// ...
}