es6 --- 类

ECMAScript 6 新引入的 class 关键字具有正式定义类的能力。class(类) 其实是对ES5 的构造函数 , 继承等进行了封装 , 语法糖等 , 使的构造函数创建,继承等像使用类一样。

类定义

与函数类型相似,定义类也有两种主要方式:类声明和类表达式。这两种方式都使用 class 关键字加大括号。

// 类声明
class Person {}     // 不需要小括号
// 类表达式
const Animal = class {}; 
类表达式

类表达式可以只有变量名, 也可以有类名和变量名

const person = class perClass{}

以这种方法创建的类 , 可以在类里面使用这个类名 , 不能在外部使用一个类名

console.log(perClass)  // ReferenceError: perClass is not defined

而如果要获取这个类名

console.log(person.name)  // perClass (字符串)

注意 : 类的定义不会被提升

类受块作用域限制 , 即如果是在 IF里面创建的类 , 也是不能被外部引用的

if (true) {
  class person {}
}
console.log(person);  // person is not defined
类的构成

类可以包含构造函数方法实例方法获取函数设置函数和静态类方法,但这些都不是必需的。空的类定义照样有效。默认情况下,类定义中的代码都在严格模式下执行。

类构造函数

constructor 关键字用于在类定义块内部创建类的构造函数。**方法名 constructor 会告诉解释器在使用 new 操作符创建类的新实例时,应该调用这个函数。**构造函数的定义不是必需的,不定义构造函数相当于将构造函数定义为空函数。

实例化

使用 new 操作符实例化 Person 的操作等于使用 new 调用其构造函数。并且会将实例化对象以 this 传入 。

class Class1 {
  constructor(name) {
    console.log(this); // Class1 {} , 类的实例化对象
    this.name = name
  }
}
const c1 = new Class1('c1')
console.log(c1); // Class1 { name: 'c1' }
console.log(c1 instanceof Class1); // ture

默认情况下,类构造函数会在执行之后返回 this 对象。,如果没有其他地方再使用到这个 this 对象 , 那么它会被销毁。

不过,如果返回的不是 this 对象,而是其他对象,那么这个对象不会通过 instanceof 操作符检测出跟类有关联因为这个对象的原型指针并没有被修改

class Class2 {
  constructor() {
    return {       // 返回非 this 的 非空对象
      name: 'c2'
    }
  }
}
const c2 = new Class2 // 无参数时 可以没有括号
console.log(c2.name); // c2
console.log(c2 instanceof Class2); // flase

类构造函数没有什么特殊之处,实例化之后,它会成为普通的实例方法(在实例里)(但作为类构造函数,仍然

要使用 new 调用)。因此,实例化之后可以在实例上引用它.

class Class3 {
  constructor(name) {
    this.name = name
  }
}
const c3 = new Class3('c3')
console.log(c3.constructor); // [Function: Class3] 一个构造函数

const c3c = new c3.constructor('c3c')
console.log(c3c); // Class3 { name: 'c3c' }

console.log(c3c instanceof c3.constructor); //true , 因为 c3c 是 new 的是 constructor 构造函数
console.log(c3c instanceof Class3); //true   
把类当成特殊函数

ECMAScript 中没有正式的类这个类型。从各方面来看,ECMAScript 类就是一种特殊函数。

使用说是函数就有 prototype 属性指向原型对象 , 而实例是类 new 出来的 , 使用 实例也有一个[[prototype]] 指向这个原型对象。

并且原型对象也有一个 constructor 指向类函数。

因为类里的 constructor 是间接实例化对象的 , 相当于辅助的 。 new 的是类 。 所以实例化对象不是属于构造函数constructor 的实例化对象 , 也就是

console.log(c3 instanceof Class3.constructor); // false

但是 , 如果把类当做一个普通函数 , 去实例函数内部的 constructor() , 那么就不一样了

const c3cc = new Class3.constructor
console.log(c3cc instanceof Class3.constructor);  // true

类可以做参数 , 也可以在创建时同时实例化对象

实例、原型和类成员

类的语法可以非常方便地定义应该存在于实例上的成员、应该存在于原型上的成员,以及应该存在于类本身的成员

实例成员

通过new调用类标识符时,都会执行类构造函数。然后会执行 constructor 构造函数 , 将新的实例对象(this) 传入 , 在 constructor 里创建实例的独有的属性和方法(即不同实例这些属性和方法是不同的)

原型方法与访问器

为了在实例间共享方法,类定义语法把在类块中定义的方法作为原型方法。

其中 constructor 中创建的属性和方法保存在不同实例里 , 地址不同 。

而类内 , constructor外创建方法 , 会被保存到类的原型对象上 , 用于各实例共享

可以把方法定义在类构造函数中或者类块中,但不能在类块中给原型添加原始值或对象作为成员数据(ES6是不允许的)

class Class4 {
  constructor(name) {
    this.name = name
  };
  fun4() {
    console.log('fun4');
  };
  age = '1';  	 // 在ES7 ,这个会被当做实例的属性去实例化给新对象
}
const c4 = new Class4('c4')
c4.fun4() // fun4
console.log(Class4.prototype.fun4); // [Function: fun4]
console.log(Class4.prototype.age); // undefined  不在原型上 , 但是在实例上是有的

类方法也支持设置和获取访问器 , 与普通对象使用方法一样

class Person { 
 set name(newName) { 
 this.name_ = newName; 
 } 
 get name() { 
 return this.name_; 
 } 
} 
let p = new Person(); 
p.name = 'Jake'; 
console.log(p.name); // Jake
静态类方法

可以在类上定义静态方法。这些方法通常用于执行不特定于实例的操作,也不要求存在类的实例。与原型成员类似;

ES6规定,静态成员每个类上只能有一个,并且必须是方法

ES7 允许它有静态属性

静态类成员在类定义中使用 static 关键字作为前缀。在静态成员中,this 引用类自身。其他所有约定跟原型成员一样

 // 定义在类本身上
 static locate() { 
 console.log('class', this); 
 }
Person.locate(); // class, class Person {}
// 在原型个实例上是没有 locate() 的
非函数原型和类成员

虽然说不支持在创建类时给类块或原型添加引用值和对象 。 但是并不是不能 。 最好是在外部添加

Class4.afe  ='age;     // 可以给类添加
Class5.prototype.h = 'h'    // 可以给原型添加

**注意的是 , 在类外给类添加的属性和方法是属于静态属性的方法的 , 在实例和原型上是没有的 。 **

**在ES6时 ,是只允许从外部添加静态方法(一个 , 且是方法) ES7 才允许在内部写静态方法和属性(不止一个) **

迭代器与生成器方法

类定义语法支持在原型和类本身上定义生成器方法

class Class5 { *
  gen1() { // 定义在原型上
    yield 1
    yield 2
    yield 3
  }
  static * gen2() {
    yield 'a'
    yield 'b'
    yield 'c'
  }
}
const c5 = new Class5
for (const i of c5.gen1()) {
  console.log(i); // 1 2 3
}
for (const i of Class5.gen2()) {
  console.log(i); // a b c
}

因为类支持生成器,那么可以给实例对象生成一个默认迭代器方法 , 让它可以迭代 , 并且迭代的内容是可以自己设置的;

class Class6 {
  constructor() {
    this.k1 = 'v1'
    this.k2 = 'v2'
    this.k3 = 'v3',
      this.arr = [1, 2, 3]
  }
    * [Symbol.iterator]() { // 第一个 * 表示这是一个生成器  ,可以使用 yield
    yield* Object.entries(this)
      // 第二个 * 和 yield 一起使用 , 后面跟迭代器
	  }
    // 这里也可以只返回迭代器 ,  return Object.entries(this) , 因为 for of 可以处理迭代器或有默认迭代器的对象的
}
const c6 = new Class6()
for (const i of c6) {
  console.log(i);
}

// [ 'k1', 'v1' ]
// [ 'k2', 'v2' ]
// [ 'k3', 'v3' ]
// [ 'arr', [ 1, 2, 3 ] ]

// 相当于 
obj = {
  k1: 'v1',
  k2: 'v2',
  k3: 'v3'
}
for (const i of Object.entries(obj)) {
  console.log(i);
}
// [ 'k1', 'v1' ]
// [ 'k2', 'v2' ]
// [ 'k3', 'v3' ]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无糖的酸奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值