es6_类(class)
创建类
通过class
关键字进行创建
类的数据类型就是函数,类本身指向构造函数
class Bar {
doStuff() {
console.log('stuff');
}
}
var b = new Bar();
b.doStuff(); //stuff
console.log(typeof Bar); //function
console.log(Bar === Bar.prototype.constructor); //true
function Bar() {
}
Bar.prototype = {
constructor: Bar,
doStuff() {
console.log('stuff');
}
}
var b = new Bar();
b.doStuff(); //stuff
由上面的代码可以看出,类的数据类型就是函数,类本身就是构造函数,class更具体来说就是es6的语法糖,起到与构造函数相同的作用。
类的所有方法都定义在类的prototype属性上,在类的实例上调用方法实际上是调用原型对象上的方法
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
class B {
toValue() {}
}
let b = new B();
console.log(b.toValue === B.prototype.toValue); //true
通过object.assign向类添加方法
class Point {
constructor() {}
}
Object.assign(Point.pototype, {
toString() {},
toValue() {}
})
类内部的所有定义方法都是不可枚举的
class Point {
constructor() {}
toString() {}
}
console.log(Object.keys(Point.prototype)); //[]
console.log(Object.getOwnPropertyNames(Point.prototype)); //["constructor","toString"]
constructor方法
通过new
命令生成对象实例时,自动调用该方法。一个类必须有constructor
方法,如果没有显式定义,一个空的constructor
方法会被默认添加。
class Point{}
//等同于
class Point{
constructor(){}
}
写在constructor函数中的代码相当于写在构造函数本身中,即Point.prototype.constructor
没有写在constructor函数中的代码,相当于写在原型对象中,即Point.prototype
类的实例
类只能通过new
来进行调用,且所有的类的实例共享一个原型对象
class Foo {
constructor() {}
}
var foo1 = new Foo();
var foo2 = new Foo();
console.log(foo1.__proto__ == foo2.__proto__); //true
//允许通过实例的__proto__属性对原型对象进行CRUD操作,其一经修改,所有的实例都会受到影响
取值函数(getter)与存值函数(setter)
class myClass {
constructor() {}
get prop() {
return 'getter';
}
set prop(val) {
console.log('setter: ' + val);
}
}
let inst = new myClass();
inst.prop = 123;
console.log(inst.prop);
上面代码中,prop
属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了。
在ES5中有Object.getOwnPropertyDescriptor
方法,用于获取指定对象的访问器属性或数据属性。
var descriptor = Object.getOwnPropertyDescriptor(myClass.prototype, 'prop');
console.log("get" in descriptor); //true
console.log("set" in descriptor); //true
属性表达式
类的属性名,可以采用表达式
let methodName = 'getArea';
class Foo {
constructor() {}
[methodName]() {
console.log('xxx');
}
}
var foo = new Foo();
foo.getArea(); //'xxx'
Class表达式
const myClass = class Me {
getClassName() {
return Me.name;
}
};
let inst = new myClass();
console.log(inst.getClassName()); //Me
//在class外部,这个类只能使用myClass引用
//Me只在class内部有定义
通过class表达式立即执行class
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('张三');
person.sayName(); //张三
- 严格模式
类和模块内部默认严格模式,所以不需要使用'use strict'指定运行模式
- 不存在提升
类不存在变量提升,即 class Foo{} 与 new Foo() 的顺序不能搞混
- name属性
ES6的类本身只是ES5的构造函数的包装,因此可以通过 Foo.name 得到 class Foo{} 的name属性(即Foo)
- Generator方法
如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。
- this指向
类的方法内部如果含有this,它默认指向类的实例。
静态方法
静态方法不会被实例继承
类相当于实例的原型对象,所有在类中定义的方法都会被实例继承,但是在一个方法前加上static
关键字,就表示该方法不会被实例继承,而是通过类来进行调用,这种方法被称为“静态方法”.
class Foo {
static classMethod() {
return 'hello';
}
}
console.log(Foo.classMethod()); //hello
var foo = new Foo();
console.log(foo.classMethod()); //foo.classMethod is not a function
静态方法的this
指向类
如果静态方法包含this
关键字,此时this指向的是类。(静态方法可以和非静态方法重名)
class Foo {
static bar() {
this.baz();
}
baz() {
console.log('world');
}
static baz() {
console.log('hello');
}
}
Foo.bar(); //hello
父类的静态方法可以被子类继承,但需要通过子类的类来进行调用
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
}
console.log(Bar.classMethod());
静态方法也可以从super对象上调用。
class Foo {
static classMethod() {
return 'hello'
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
console.log(Bar.classMethod());
实例属性的新写法
实例属性可以定义在constructor()
方法里面的this
上面,也可以定义在类的最顶层。
class IncreasingCounter {
constructor() {
this._count = 0;// 定义在这儿相当于定义在构造函数内
}
get value() {
console.log('Getting the current value');
return this._count;
}
increment() {
this._count++;// 相当于定义在原型对象中
}
}
var inc1 = new IncreasingCounter();
var inc2 = new IncreasingCounter();
inc1.increment();
console.log(inc1.value); //Getting the current value 1
console.log(inc2.value); //Getting the current value 0
class IncreasingCounter {
_count = 0;// 相当于定义在原型对象
get value() {
console.log('Getting the current value');
return this._count;
}
increment() {
this._count++;
}
}
var inc1 = new IncreasingCounter();
var inc2 = new IncreasingCounter();
inc1.increment();
console.log(inc1.value);
console.log(inc2.value);
写在类的顶端的属性和写在constructor
方法中的属性是有区别的。写在类的顶端的属性相当于写在类的原型对象内,而写在constructor
方法中的属性则是写在构造函数中的。
静态属性
class MyClass {
static myStaticProp = 45;
constructor() {
this.getVal = function () {
console.log(MyClass.myStaticProp);
}
}
}
var c = new MyClass();
c.getVal(); //45
类的静态属性只属于类,与实例无关