ES6:class的引入
概要
- ES6的class语法仅仅只是一个语法糖,在ES5中同样可以实现,新的class语法只是为了让对象原型的写法更加清晰,更像面向对象编程语法。
class Point{
constructor(x,y){
this.x = x;
this.y = y;
}
toString(){
console.log( '(' + this.x + ',' + this.y + ')');
}
}
// 调用
let a = new Point(1,2);
a.toString();
//输出
(1,2)
-
在类的实例上调用方法,实际上就是在调用原型的方法;
-
类内部定义的方法都是不可枚举的;
-
类必须使用new来调用,否则会报错;
class表达式
- 与函数一样,class也可以用表达式的形式定义;
const myclass = class me{
getClassName(){
return me.name;
}
}
let a = new myclass();
a.getClassName();
// 输出
"me"
- 从上面的例子可以看出,me只在内部class中有用,外部调用时还是利用变量名称myclass;
不存在变量提升
- 类不存在变量提升,因此在类定义之前不能够调用它;
私有方法和属性
- 在ES6的class中没有提供private关键字,但目前有一种提案,采用#作为私有标志
class Me{
#name
#age = 20
// #getmoney() {return 100}
constructor(name){
this.#name = name;
}
getit(){
console.log('age:' + this.#age);
}
}
let a = new Me('yivi');
a.getit();
//输出
age:20
//如果尝试访问私有属性
a.#name;
//报错
“Private field '#name' must be declared in an enclosing class”
this的指向
- 类的内部若含有this,他将默认指向类的实例。但有时单独使用该方法可能会报错。
class Logger{
printName(name = 'yivi'){
this.print(`${
name},yyds!`);
}
print(text){
console.log(text);
}
}
const logger = new Logger();
const {
printName} = logger;
printName(); //报错
- 上述代码中,this的指向默认指向实例,但如果提取出来单独使用,则this会指向当前的运行环境;
- 解决方法是:在定义类时将this存储起来;
//方法1
class Logger{
constructor(){
// 将当前this绑定到printName函数上
this.printName = this.PrintName.bind(this);
}
printName(name = 'yivi'){
this.print(`${
name},yyds!`);
}
print(text){
console.log(text);
}
}
const logger = new Logger();
const {
printName} = logger;
printName(); //“yivi,yyds!”
- 还可以用箭头函数
// 方法2
class Logger{
constructor(){
this.printName = (name = 'yivi')=>{
this.print(`${
name},yyds!`)
}
}
}
getter和setter
- 类的内部也可以设置get和set关键字对某个属性设置存值函数和取值函数。
class Myclass{
constructor(){
}
get prop(){
return 'i am getter!';
}
set prop(val){
console.log("prop set as "+ val);
}
}
let init = new Myclass();
init.prop = 123;
init.prop;
//prop set as 123
//i am getter
静态方法和静态属性
- 类相当于实例的原型,在类的函数前添加static关键字,代表静态方法,只能通过类访问,实例将不会继承其方法。
class Foo{
static mymethod(){
console.log('i am static!');
}
}
let a = new Foo();
Foo.mymethod();
a.mymethod();
// i am static!
// TypeError: foo.mymethod is not a function
- 父类的静态方法可以被子类继承!子类可通过super调用父类方法。
class Father{
static mymethod(){
console.log('i am static!');
}
}
class Son extends Father{
static sonmethod(){
console.log('hello!' + super.mymethod() );
}
}
Son.mymethod();
// i am static!
Son.sonmethod();
// hello!i am static!
- 静态属性和静态方法相同,也是在属性前添加static关键字。
new.target属性
- ES6在类的内部定义了一个new.target属性,返回new命令锁作用的构造函数
class Person{
name;
constructor(name){
if(new.target == Person){
this.name = name;
}else{
throw new Error('请使用new生成实例');
}
}
}
let a = new Person('yivi');
- 子类继承父类时,new.,target会返回子类!
class father{
constructor(){
console.log(new.target == father);
}
}
class son extends father{
constructor(){
super();
}
}
let a = new son();
// false;
关于子类的this
- 子类的构造函数中,必须调用了super后,在可以使用this关键字,否则会报错;这是因为子类没有自己的this对象,只有继承父类的this对象。
- 如果子类没有定义constructor,那么会自动添加包含super关键字的constructor。
class Father{
}
class Son extends Father{
constructor(...args){
//自动添加
super(...args);
}
}
let a = new Son();
a instanceof Father;
a instanceof Son;
// true
// true
super关键字
-
super()这个方法只能用在子类的constructor属性中,用在其他地方会报错!
-
super关键字作为对象在普通方法中指向父类的原型对象,在静态方法中指向父类。
class A{
constructor(){
this.p = 123;
}
}
class B extends A{
constructor(){
super();
// 这里的super指向A.prototype
console.log(super.p);
}
get m(){
// 这里的super指向A
console.log(super.p);
}
}
let a = new B();
a.m;
// 123
// undefined
- Es6规定,通过super调用父类方法时,super会绑定子类的this。也就是说,此时的super就是子类的this
class A{
constructor(){
this.x = 1;
}
print(){
console.log(this.x);
}
}
class B extends A{
constructor(){
super();
this.x = 2;
}
getx(){
super.print();
}
}
let a = new B();
a.getx();
// 2;
类的prototype和__proto__属性
- 子类的__proto__属性表示构造函数的继承,指向父类;
- 子类的prototype属性的__proto__属性表示方法的继承,指向父类的prototype;
class A{
}
class B extends A{
}
B.__proto__ === A //true
B.prototype.__proto__ === A.prototype //true