二.静态方法
- 类相当于实例对象的原型对象,所以所有在类上定义的方法,都会被实例继承。
如果在一个方法前加上static关键字,那么就表示该方法不会被实例继承,而是直接通过类来调用
class Foo{
static getName(){
return 'yiye'
}
}
console.log(Foo.getName())
console.log(new Foo().getName())
如果在静态方法中包含this关键字,那么这个this指的是类,而不是实例!
class Foo{
static bar(){
return this.func()
}
static func(){
console.log('static方法是类直接调用')
}
func(){
console.log('普通方法是类的实例来调用')
}
}
Foo.bar()
var f=new Foo()
f.func()
父类的静态方法可以被子类继承,子类可以通过super.xxx()来调用父类的方法
class Foo{
static getName(){
return 'foo'
}
}
class child extends Foo{
static print(){
console.log('父类的名字是:'+super.getName())
}
}
child.print()
三.实例属性的简洁写法
- 实例属性除了可以定义在constuctor构造函数中之外。还可以定义在类的顶层
和类的方法处于同一层级
class Foo{
name='foo';
get val(){
return this.name;
}
print(){
console.log('name:'+this.name)
}
}
var f=new Foo()
console.log(f.name)
console.log(f.val)
f.print()
这样写的好处就在于一眼看过去就知道该类具有什么实例属性
四.静态属性
在类的外部想要定义static静态属性/方法可以直接赋值
class Foo{}
Foo.a='yiye'
console.log(Foo.a)
Foo.func=function(){
return 'i am yiye'
}
console.log(Foo.func())
如果要定义实例方法(类的实例可以调用的方法)就通过prototype定义在类的原型上
五.私有方法和私有属性
- 目前ES6还没有提供私有方法和私有属性,只有ts才能提供private关键字。
- 替代方案是约定命名为
_xxx(){}这种为私有方法,_xxz为私有属性 - 另一种方法是使用
Symbol来模拟,但是在外部依旧可以通过Reflect.ownKeys()来获取
const bar=Symbol('bar')
const foo=Symbol('foo')
class F{
[bar](){
this[foo]='yiye'
return this[foo]
}
getName(){
console.log('ddd')
}
}
var f=new F()
f.getName()
console.log(f[bar]())
console.log(Reflect.ownKeys(f))
console.log(Reflect.ownKeys(f.__proto__))
console.log(Object.keys(f.__proto__))
console.log(Object.getOwnPropertyDescriptor(f.__proto__,'getName'))
六.new.target属性
- new是从构造函数生成实例对象的命令,ES6为new命令引入了一个
new.target属性 如果构造函数不是通过new或者Reflect.constructor()调用的,net.target会返回undefined注意:如果是子类继承父类,那么父类内部的new.target返回的是子类!
function person(name){
if(new.target!==undefined){
this.name=name;
}else{
throw new Error('必须使用new命令来生成实例')
}
}
var per=new person('yiye')
console.log(per.name)
class One{
constructor(name) {
if(new.target===One){
console.log(name)
}else{
console.log(new.target)
throw new Error('必须使用new命令生成类的实例')
}
}
}
new One('hh')
class C extends One{
constructor() {
super('bb')
}
}
new C()
也可以使用这个属性来实现抽象类,判断new.target为本类的时候报错,不为本类才可以和抽象类一致(只能被继承)
七.class的继承介绍
简介
- class可以通过extends实现继承,比起es5修改原型链实现继承要清晰
class继承必须在构造器函数中使用super()方法,用于表示父类的构造函数,用于新建父类的this对象子类必须在构造器函数中调用super方法是因为子类自己的this对象必须先通过父类的构造函数完成塑造,得到和父类相同的实例属性和方法然后才能继续加上子类自己的实例属性和方法,如果不调用super方法,子类就得不到this对象,就没办法新建实例
class A{
constructor(name) {
this.name=name;
}
}
class B extends A{
constructor(name) {
this.name=name;
console.log(this.name)
}
}
console.log('不调用super(),类也是可以使用的',B.name);
console.log(new B('aa').name)
注意:必须在调用super()之后才能使用this关键字(这是因为子类实例的构建基于父类实例,所以必须先使用super()调用父类实例)即使不声明构造器函数,class也会默认创建一个constructor函数
class A{
constructor(name) {
this.name=name;
}
}
class B extends A{
constructor(...args) {
super(...args)
}
}
console.log(new B('hhhh').name)
子类会继承父类的属性和方法
子类extends父类,所以子类.__proto__全等于父类,所以相当于父类挂载到子类原型链上此外,即使是父类的静态方法,也会被子类所继承的!
class Father{
speak(){
console.log('speak')
}
}
class Child extends Father{
eat(){
console.log('eat')
}
}
console.log(Child)
console.log(Child.prototype)
console.log(Child.__proto__ === Father)
Object.getPrototypeOf()可以用于获取子类的父类
console.log(Object.getPrototypeOf(Child)) //class Father
本文参考阮一峰ES6教程