es6中的Class


基本用法

// es5造类
function Person(name,age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function() {
  return this.name;
}
let p = new Person('AIpoem',19);
// es6造类
class Person(){
  // 构造方法,实例化new的时候立即被调用
  constructor(name,age) {
    this.name = name;
    this.age = age;
  }
  sayName() {
    return this.name;
  }
  sayAge() {
    return this.age;
  }
}
let p = new Person('AIpoem',19);

prototype 属性,在 ES6 的“类”上面也存在。事实上,类的所有方法都定义在类的prototype属性上

class Person {
  constructor() {
  }
  sayName() {
  }
  sayAge() {
  }
}
// 等同于
Person.prototype = {
  constructor() {}
  sayName() {}
  sayAge() {}
};

所以,在类的实例上调用方法,实际上就是调用原型上的方法

class Person {}
const p = new Person();

p.constructor === Person.prototype.constructor  // true

pPerson类的实例,它的constructor()方法就是Person类原型上的constructor()方法

所以类的新方法可以添加在prototype对象上,使用Object.assign()方法可以很方便地一次向类添加多个方法

class Person() {
}
Object.assign(Person.prototype, {
  sayName() {},
  sayAge() {}
})

prototype对象的constructor()属性,直接指向"类"的本身

Person.prototype.constructor === Person // true

constructor 方法

  • constructor 方法是类的默认方法,通过new命令生成对象实例的时候,自动调用constructor 方法
  • 一个类必须有constructor 方法,如果没有显式定义,会默认添加一个constructor()方法
class Person {
}
// 等同于
 class Person {
   constructor() {}
 }

类的实例

实例的属性:
除非显式定义在其本身上(定义在this对象上),否则都是定义在原型上(定义在class上)

//定义类
class Person{
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  toString() {
    return '(' + this.name + ', ' + this.age + ')';
  }
}
const p = new Person('AIpoem',19);
console.log(p.toString());		// (AIpoem, 19)
console.log(p.hasOwnProperty("name"));	// true
console.log(p.hasOwnProperty("age"));	// true
console.log(p.hasOwnProperty("toString")); // false
console.log(p.__proto__.hasOwnProperty("toString")) // true

上面代码中,nameage都是实例对象p自身的属性(因为定义在了this对象上),而toString()是原型对象的属性(因为定义在了Person类上)

类的所有实例共享一个原型对象:

const p1 = new Person('AIpoem1',19);
const p2 = new Person('AIpoem2',20);

p1.__proto__ === p2.__proto__
//true

实例p1p2的原型都是Person.prototype,所以__proto__属性是相等的
这意味着,可以通过实例的__proto__属性为添加方法:

const p1 = new Person('AIpoem1',19);
p1.__proto__.sayName = function() {
  return this.name;
}
const p2 = new Person('AIpoem2',19);
console.log(p1.sayName());	// AIpoem1
console.log(p2.sayName());  // AIpoem2

在实例p1的原型上添加了一个sayName()方法,由于p1p2共享一个原型,所以p2也能调用sayName()方法
⚠️:这意味着使用实例的__proto__属性改写原型,必须相当谨慎,因为会影响到所有的实例


getter和setter

在类的内部可以使用getset关键字,对某个属性设置存值函数和取值函数

class MyClass{
  constructor() {
  }
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter:' + value);
  }
}
const c = new MyClass();
c.prop = 123;
// setter: 123
c.prop
// 'getter'

存值函数取值函数是设置在属性的Descriptor对象上的


Class表达式

和函数一样,类也可以使用表达式定义

const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};

这个类的名字是Me,但是Me只在Class的内部可用,指代当前类
Class 外部,这个类只能用MyClass引用

如果类的内部没用到的话,可以省略Me,也就是可以写成下面的形式:

const MyClass = class { /* ... */ };

静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承
在一个方法前加上static关键字,该方法不会被实例继承,而是通过来调用,这就是静态方法

class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

上面代码中,classMethod是静态方法,可以直接在上调用(Foo.classMethod()),而不是在实例上调用

⚠️:静态方法中的this关键字,指的是,而不是实例

class Foo {
  static bar() {
    this.baz();
  }
  static baz() {
    console.log('hello');
  }
  baz() {
    console.log('world');
  }
}

Foo.bar() // hello

上面代码中,静态方法bar()调用了this.baz(),等同于调用Foo.baz()。而且还能看出:静态方法可以与非静态方法重名


实例属性的新写法

实例属性可以定义在:

  • constructor()里的this
  • 最顶层
class Foo {
  constructor() {
    this.count = 0;
  }
}
class Foo {
  count = 0;
  constructor() {
  // ...
  }
}

静态属性

类本身的属性,是静态属性,不是定义在实例(this)上的属性

class Foo {
  static prop = 1;
}

上面的代码为Foo类定义了一个静态属性prop


私有方法和私有属性

私有方法私有属性,是只能在内部访问的方法属性外部不能访问

私有方法的定义:
一种方法是将私有方法移除类,因为类内部的所有方法都是对外可见

class Student {
  setName(name) {
    person.call(this,name);
  }
}
function person(name) {
  return this.name = name;
}

let s = new Student();
s.setName("AIpoem");
console.log(s);
// Student{name: 'AIpoem'}

上面代码中,sayName()是公开方法,内部调用了person.call(this,name),这使得person()实际上成为了Student类的私有方法

还有一种方法是私有方法名字命名为一个Symbol

const bar = Symbol('bar');
const snaf = Symbol('snaf');

class myClass{
  // 公有方法
  foo(baz) {
    this[bar](baz);
  }
  // 私有方法
  [bar](baz) {
    return this[snaf] = baz;
  }
}

let s = new myClass();
s.foo(111);
console.log(s);
// myClass {Symbol(snaf): 111}

上面代码中,barsnaf都是Symbol值,一般情况下无法获取到它们,因此达到了私有方法私有属性的效果

有一个提案,为类加了私有属性和私有方法,方法是在属性名或方法名之前使用#表示

class IncreasingCounter {
  #count = 0;
  increment() {
    this.#count++;
  }
}

上面代码中,#count就是私有属性,只能在类的内部使用(this.#count)

class Foo {
  #a;
  #b;
  constructor(a,b) {
    this.#a = a;
    this.#b = b;
  }
  #sum() {
    return this.#a + this.#b;
  }
}

上面代码中,#sum()就是一个私有方法


in运算符-判断是否存在某个私有属性

in运算符,用来判断私有属性

class A {
  use(obj) {
    if (#foo in obj) {
      // 私有属性 #foo 存在
    }else {
      // 私有属性 #foo 不存在
    }
  }
}

子类从父类继承的私有属性,也可以使用in运算符来判断

class A {
  #foo = 0;
  static test(obj) {
    console.log(#foo in obj);
  }
}

class SubA extends A {};

A.test(new SubA()) // true

静态块

允许在内部设置一个代码块,在类生成运行一次,主要作用是静态属性进行初始化

class C {
  static x = 1;
  static y;
  static z;

  static {
    try {
      const obj = doSomethingWith(this.x);
      this.y = obj.y;
      this.z = obj.z;
    } catch {
      this.y = ...;
      this.z = ...;
    }
  }
}

上面代码中的static代码块就是静态块,它的好处是将静态属性yz的初始化写进了类的内部,而且只运行一次

⚠️:每个类只能有一个静态块,在静态属性声明之后运行,静态块的内部不能有return语句

静态块还可以将私有属性和类的外部代码分享:

let getX;

class C {
  #x = 1;
  static {
    getX = obj => obj.#x;
  }
}

console.log(getX(new C())); // 1

上面代码中,如果类外部的getX()希望获取到#x属性,以前要写在类的constructor()里,这样每次新建实例都会定义一次getX()
现在写在静态块里,只在类生成的时候定义一次


new.target 属性

new.target属性可以用来确定构造函数是怎么调用的
该属性一般用在构造函数之中,返回**new命令作用于的那个构造函数**
如果构造函数不是通过new命令或者Reflect.construct()调用的,new.target会返回undefined

function Person(name) {
  if(new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必需使用new命令生成实例')
  }
}

上面代码确保构造函数只能通过new命令调用


参考:
https://es6.ruanyifeng.com/#docs/class#简介

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值