Es6-class类详解
ES6 引入了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用ES6的“类”改写,就是下面这样。
1. 基本语法
定义一个类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
const p = new Point(1,2)
上面代码,我们定义了一个Point类,可以看见里面有一个constructor方法,这个就是构造函数,this关键字就是当前的实例对象
使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
Point类除了构造方法,还定义了一个toString()方法,定义toString()方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了,方法与方法之间不需要逗号分隔。
class Point {
}
typeof Point // "function"
Point === Point.prototype.constructor // true
在上面代码中我们使用typeof去查看我们的Point是什么类型,出来的结果是函数,类的数据类型就是函数,类本身就指向构造函数。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
上面代码中,constructor()、toString()、toValue()这三个方法,其实都是定义在Point.prototype上面。
class B {}
const b = new B();
b.constructor === B.prototype.constructor // true
上面代码中,b是B类的实例,它的constructor()方法就是B类原型的constructor()方法。
因为类方法都是定义在prototype上,所以我们可以直接添加在原型上
class B {}
B.prototype.fun = ()=>{}
B.prototype.ron = ()=>{}
prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。
Point.prototype.constructor === Point // true
constructor方法
constructor()是类的自带的一个方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加,所以即使你没有添加构造函数,也是有默认的构造函数的。一般constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。
//使用class声明一个类
class Person{
//每个类都有构造方法constructor,实例化对象时执行构造方法
//即使你不写构造方法,浏览器也会自动补全,但没有可执行的内容。
constructor(name,age){
//这里的this类似于构造函数中返回的实例对象。
//一般在构造方法中定义属性,不定义方法
this.name = name;
this.age = age;
}
//这里定义方法等同于在构造函数的原型上定义方法,是实例的共同方法
speak(){
console.log('speak');
}
}
//实例化一个Person对象:
const p1 = new Person('小明',18);
const p2 = new Person('小猪',19);
const v = `${p1.name},${p1.age},${p2.name},${p2.age}`;
console.log(v)//小明,18,小猪,19
console.log(p1.speak == p2.speak); //true
类的两种定义方式
//类的两种定义方式
//一、声明形式
class Person1{
constructor(){}
speak(){}
}
//二、表达式形式
const Person2 = class{
constructor(){}
speak(){}
}
实例的属性和方法
class Person1{
age = 0;
sex = 'male';
constructor(){}
speak(){
return "我是speak"
}
}
const per1 = new Person1();
const per2 = new Person1();
console.log(per1.age,per1.hasOwnProperty("age"));//0 true
console.log(per2.speak(),per2.hasOwnProperty("speak"),Person1.prototype.hasOwnProperty("speak"));//我是speak false true
静态属性和方法(类的属性和方法)
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
声明静态方法:在方法名前加static
class MyClass {
static myStaticProp = 42;
constructor() {
console.log(MyClass.myStaticProp); // 42
}
}
const MyClass = class{
constructor(){}
static speak(){
console.log('静态');
console.log(this); //this指向class
}
}
//调用静态方法:由类调用
MyClass.speak()
私有属性和方法
什么是私有:
只能在类的内部访问的方法和属性,外部不能访问。
为什么需要私有属性和方法:
类的属性和方法都是公开的,公有的属性和方法可以被外界修改,造成意想不到的错误,所以需要私有属性
class Widget {
// 公有方法
foo (baz) {
this._bar(baz);
}
// 私有方法
_bar(baz) {
return this.snaf = baz;
}
// ...
}
上面代码中,_bar()方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法。
另一种方法将私有属性和方法移出类
class Widget {
foo (baz) {
bar.call(this, baz);
}
// ...
}
function bar(baz) {
return this.snaf = baz;
}
上面代码中,foo是公开方法,内部调用了bar.call(this, baz)。这使得bar()实际上成为了当前类的私有方法。
//Person.js
let name = "";
class Person{
constructor(username){
//name是类的属性不是实例的属性
// console.log(Person.hasOwnProperty("name")) true
name = username;
}
speak(){
console.log('speak');
}
getName(){
return name;
}
}
//暴露Person
window.Person = Person;
//index.js
const p = new Person('Alex');
console.log(p.getName()); //Alex
// console.log(p.hasOwnProperty("name")) false
还有一种方法是利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
// 公有方法
foo(baz) {
this[bar](baz);
}
// 私有方法
[bar](baz) {
return this[snaf] = baz;
}
// ...
};
上面代码中,bar和snaf都是Symbol值,一般情况下无法获取到它们,因此达到了私有方法和私有属性的效果。但是也不是绝对不行,Reflect.ownKeys()依然可以拿到它们。
ES2022正式为class添加了私有属性,方法是在属性名之前使用#表示。
class IncreasingCounter {
#count = 0;
get value() {
console.log('Getting the current value!');
return this.#count;
}
increment() {
this.#count++;
}
}
然可以拿到它们。
ES2022正式为class添加了私有属性,方法是在属性名之前使用#表示。
class IncreasingCounter {
#count = 0;
get value() {
console.log('Getting the current value!');
return this.#count;
}
increment() {
this.#count++;
}
}
上面代码中,#count就是私有属性,只能在类的内部使用(this.#count)。如果在类的外部使用,就会报错。
1万+

被折叠的 条评论
为什么被折叠?



