类的由来
ES6 的
class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
- JavaScript 语言中,生成实例对象的传统方法是通过构造函数。
function Point(x,y){
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
- 用 ES6 的class改写,就是下面这样
class Point {
// constructor()方法就是构造方法
constructor(x, y) {
// this关键字则代表实例对象
this.x = x;
this.y = y;
} // 方法与方法之间不需要逗号分隔,加了会报错
// toString()方法不再需要 function 关键字
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
- ES6 的类,完全可以看作构造函数的另一种写法
class Point {
// ...
}
typeof Point // "function"
// prototype对象的constructor()属性,直接指向“类”的本身
Point === Point.prototype.constructor // true
- 使用方法:直接对类使用new命令,跟构造函数的用法完全一致
class Bar {
doStuff() {
console.log('stuff');
}
}
const b = new Bar();
b.doStuff() // "stuff"
- ES6类上依旧有构造函数的
prototype
属性,类的所有方法都定义在类的prototype
属性上面
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
- 在类的实例上面调用方法,其实就是调用原型上的方法
class B {}
const b = new B();
// b是B类的实例,它的constructor()方法就是B类原型的constructor()方法
b.constructor === B.prototype.constructor // true
- 类的属性名,可以采用表达式。
let methodName = 'getArea';
class Square {
constructor(length) {
// ...
}
[methodName]() {
// ...
}
}
// 等同于
class Square {
constructor(length) {
// ...
}
getArea() {
// ...
}
}
- 与函数一样,类也可以使用表达式的形式定义。
// 定义
const MyClass = class Me{
getClassName() {
return Me.name;
}
}
// 使用
let inst = new MyClass();
inst.getClassName() // Me
Me.name // ReferenceError: Me is not defined
// 如果类的内部没用到的话,可以省略Me
const MyClass = class { /* ... */ };
// 采用 Class 表达式,可以写出立即执行的 Class
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('张三');
person.sayName(); // "张三"
constructor 方法
constructor()
方法是类的默认方法,通过new
命令生成对象实例时,自动调用该方法。
- 一个类必须有
constructor()
方法 - 即使你不写,JavaScript 引擎也会给你默认添加一个空的
constructor()
方法
// 定义一个空的类 Point
class Point {
}
// 他会等同于
class Point {
constructor(){
}
}
constructor
方法默认返回实例对象(即this
)- 也可以指定他返回的实例对象
// 默认返回
class Point {
constructor(){}
}
new Point() instanceof Point // true
// 指定返回
class Foo {
constructor(){
// 返回一个全新的对象,结果导致实例对象不是Foo类的实例
return Object.create(null)
}
}
new Foo() instanceof Foo // false
- 类必须使用
new
调用,否则会报错 - 而普通构造函数不用
new
也能执行
class Foo {
constructor(){}
}
new Foo()
Foo()
// TypeError: Class constructor Foo cannot be invoked without 'new'
类的实例
- 生成类的实例也必须使用
new
命令
class Foo {
constructor(){}
}
// 正确写法
let foo = new Foo(6,4);
// 错误写法
let foo = Foo(6,4)
- 实例的属性定义有两种情况:
- 第一种:定义在自身的
this
对象上 - 第二种:定义在原型上,即
class
上
class Foo {
constructor(){
// 第一种情况
this.x = x,
this.y = y
}
// 第二种情况
toString(){
return '(' + this.x + ', ' + this.y + ')';
}
}
let foo = new Foo(6,4)
foo.toString(6,4) // (6,4)
// hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性
foo.hasOwnProerty("x") // true
foo.hasOwnProperty('y') // true
foo.hasOwnProperty('toString') // false
foo.__proto__.hasOwnProperty('toString') // true
- 类的实例共享一个原型对象
let foo = new Foo(3,4)
let fvv = new Foo(5,2)
foo.__proto__ ==== fvv.__proto__ // true
取值函数和存值函数(getter、setter)
- 在类的内部可以使用
get
和set
关键字 - 对某个属性设置存值函数和取值函数,拦截该属性的存取行为
class MyClass {
constructor(){}
get prop(){
return "getter"
}
set prop(value){
console.log('setter: '+value);
}
}
let inst = new MyClass();
inst.prop = 124 // setter: 124
inst.prop // 'getter'
静态方法和静态属性(static)
静态方法:
在类中定义的方法,前面加上
static
关键字,表示静态方法
- 类相当于实例的原型,所有在类中定义的方法,都会被实例所继承
- 而用
static
声明的方法不会被实例继承,而是直接通过类来掉用,称之为静态方法
class MyClass {
// static 关键字表示这是一个静态方法
static myFunction (){
return "hello world"
}
}
// 通过类直接调用静态方法,成功
MyClass.myFunciton() // "hello world"
// 声明类的实例对象
let me = new MyClass()
// 通过实例对象调用静态方法,报错
me.myFunction() // // TypeError: foo.classMethod is not a function
- 静态方法
this
指向类,而非静态方法方法this
指向类中的实例对象 - 静态方法可以与非静态方法重名
class MyClass {
static fn(){
this.fun()
}
static fun(){
return "hello"
}
fun(){
return "world"
}
}
MyClass.fun() // "hello"
- 父的静态方法可以被子类继承
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
}
Bar.classMethod() // 'hello'
- 静态方法也是可以从super对象上调用的。
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
Bar.classMethod() // "hello, too"
静态属性:
静态属性指的是
Class
本身的属性,即Class.propName
,而不是定义在实例对象(this
)上的属性。
// 老写法
class Foo {
// ...
}
Foo.prop = 1;
// 新写法
class Foo {
static prop = 1;
}