9、类静态方法
9.1、基本概念
所谓静态方法,在class指专属于class本身的方法,而且不会被类的实例所继承。
如代码:
class Foo {
static test() {
console.log("this is static")
}
}
Foo.test() // this is static
let p = new Foo()
p.test() // Uncaught TypeError: p.test is not a function
至于实现原理,很简单。只有构造函数原型链上(prototype属性)的方法才会被构造函数的实例所继承。
因此,把静态方法直接挂载在类本身上,而不是类的原型链上,即可以。
如何证明这一点呢?普通方法是不行的,原因在于通过类声明的方法,他的enumberable的属性是false,因此是不可以枚举的。
例如Object.keys(Foo)
之类的方法是不可行的
有两个办法:
- 通过
console.dir(Foo)
来查看整个Foo类的原型链; - 通过
Object.getOwnPropertyNames(Foo)
或Reflect.ownKeys(Foo)
来查看Foo上面有哪些属性,这两个方法可以查看enumberable值为false的属性。参照博客对象的扩展(3)当枚举、原型链遇见对属性的操作
Object.getOwnPropertyNames(Foo) // ["length", "prototype", "test", "name"]
Reflect.ownKeys(Foo) // ["length", "prototype", "test", "name"]
9.2、this
静态方法的this指向谁呢?
我们知道,对象的方法中的this,指向对象自己。
而类是对象,类的静态方法就是对象的方法,因此,类的静态方法里的this也指向类本身。
class Foo {
static test() {
return this
}
}
Foo.test() === Foo // true
9.3、继承的静态方法
目前还没涉及到类的继承,但可以给出一个结论:
- 类的静态方法可以被继承;
- 父类的静态方法被继承后,this指向子类;
另外提一句,类的继承,是让子类的__proto__
属性指向父类。
9.4、类没有静态属性
至少目前没有。
当然,可以在类的constructor方法里,通过this.xx设置类的静态属性,但不能直接通过static xx
这样的方式来定义静态属性。
10、new.target
10.1、基本概念
简单来说,这个属性用于表示当函数通过new来调用时(即函数被当做构造函数),new命令作用的那个构造函数是谁。
他有以下几个规律:
1、被用在函数内部,函数外部直接调用会报错;
new.target; // Uncaught SyntaxError: new.target expression is not allowed here
2、当函数被作为构造函数new时,new.target指向构造函数;
function Test() {
return new.target
}
new Test() === Test; // true
3、当new.target处于类的constructor属性中时,指向类本身
class Foo {
constructor() {
return new.target
}
}
new Foo() === Foo; // true
4、当父类被子类继承时,父类中的constructor的new.target指向子类(而非父类)。
这个比较特殊,在es5中似乎实现起来很复杂
class Foo {
constructor() {
console.log(new.target === Bar)
}
}
class Bar extends Foo {
constructor() {
super() // 这个表示是父类的构造函数
console.log(new.target === Bar)
}
}
new Bar()
// true
// true
5、当函数并没有被new所调用时,而是普通调用,那么new.target的值是undefined
function Test() {
return new.target
}
Test() // undefined
10.2、应用
由于这个特点,因此在父类的constructor函数内,可以通过new.target是否等于父类,来限制允对父类的使用。
例如:
1、如果只允许在等于父类的情况下执行,否则报错,那么该父类是无法被继承的;
2、如果只允许在不等于父类的情况下执行,否则报错,那么该父类是无法被单独使用的,必须被继承后才能使用。