文章目录
class的基本语法
class 声明创建一个基于原型继承的具有给定名称的新类。
ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
class Polygon {
constructor(height, width) {
this.area = height * width;
}
}
console.log(new Polygon(4, 3).area);
// expected output: 12
和类表达式一样,类声明体在严格模式下运行。构造函数是可选的。
类声明不可以提升(这与函数声明不同)。
和ES5的写法对比
ES6 的class与ES5写法的几个核心注意点:
- ES5 的构造函数Point,对应 ES6 的Point类的构造方法。
- 类的所有方法都定义在类的prototype属性上面。
- 定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了
- 方法之间不需要逗号分隔,加了会报错
- ES6的class使用方法与ES5的构造函数一模一样
在类的实例上面调用方法,其实就是调用原型上的方法。
上面代码表明,类的数据类型就是函数,类本身就指向构造函数。
类的内部所有定义的方法,都是不可枚举的
(non-enumerable)。
class Point{
constructor(x,y){
}
fn(){
}
}
console.log(Object.getOwnPropertyNames(Point.prototype));//(2) ["constructor", "fn"]
console.log(Object.keys(Point.prototype));//[]
通过Object.assign方法往类的原型上添加的方法,
constructor不可枚举, 其他的可以枚举
class的constructor()
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象
class Ep{
}
const c = new Ep()
console.log(c);
console.log(c instanceof Ep); //true
class Ep{
constructor(){
return {}
}
}
const c = new Ep()
console.log(c);//{}
console.log(c instanceof Ep); //false
得是在创造class时就定义设置的, 在创造完class后,通过Object.assign的方式是没法改变构造函数的返回值的
class的唯一调用方式
类必须使用new调用,否则会报错。
class的get和set
class MyClass{
get myAtribute(){
return 'getter'
}
set myAtribute(value){
console.log(`setter:${value}`);
}
}
const a = new MyClass() //setter:5
a.myAtribute = 5
console.log(a.myAtribute); //getter
上面代码中, attribute属性有对应的存值函数和取值函数, 因此赋值和读取行为都被自定义了。
存值函数和取值函数是设置在属性的 descriptor 对象上的。
上面的写法等价于
表达式表示法
类的属性名,可以采用表达式
class表达式
上面代码使用表达式定义了一个类。需要注意的是,这个类的名字是Me,但是Me只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用MyClass引用。
如果类的内部没用到的话,可以省略Me,
一些注意事项
1,类和模块的内部,默认就是严格模式
2,不存在提升
上面代码中,Foo类使用在前,定义在后,这样会报错,因为 ES6 不会把类的声明提升到代码头部。
name 属性
由于本质上,ES6 的类只是 ES5 的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性。
printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到print方法而报错。
怎么解决这个问题
一个比较简单的解决方法是,在构造方法中绑定this,这样就不会找不到print方法了。
bind之后返回的函数里面的this就永久锁死了
另一种解决方法是使用箭头函数。
箭头函数位于构造函数内部,它的定义生效的时候,是在构造函数执行的时候。这时,箭头函数所在的运行环境,肯定是实例对象,所以this会总是指向实例对象。
class的属性的定义方式
属性既可以 定义在构造函数里面 也可以定义在构造函数外面
class的静态属性和方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。静态方法可以与非静态方法重名。
class Coder{
static coding(){
console.log(this);
return '我会敲代码'
}
coding(){
return '正在学习class语法'
}
}
console.log(Coder.coding()); //我会敲代码
const xiao_hong = new Coder()
console.log(xiao_hong.coding());
父类的静态方法,可以被子类继承
静态方法也是可以从super对象上调用的。
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
目前,只有这种写法可行,因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性
怎么实现class的私有方法和属性
私有方法和私有属性:是只能在类的内部访问的方法和属性,外部不能访问。
这是常见需求,有利于代码的封装,但 ES6 不提供,只能通过变通方法模拟实现。
方法是利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。
new.target属性
ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。
Class 内部调用new.target,返回当前 Class。