es6 类 和 继承

只使用 ECMAScript 5 的特性来模拟类似于类的行为。各种策略都有自己的问题,也有相应的妥协。正因为如此,实现继承的代码也显得非常冗长和混乱。

为解决这些问题,ECMAScript 6 新引入的 class 关键字具有正式定义类的能力。类是 ECMAScript 中新的基础性语法糖结构,背后使用的仍然是原型和构造函数的概念。

1.类的定义 和 构成
与函数类型相似,定义类也有两种方式:类声明 和 类表达式。

// class 声明
class Person{}
//类表达式
let Person = class {};

与函数表达式类似,类表达式在他们被求值前也不能引用。与函数定义不同的是,函数声明可以提升,但类定义不能。
函数受函数作用域限制,类受块作用域限制。

类可以包含构造函数、实例方法、获取函数、设置函数和静态类方法。默认情况下,类定义中的代码都是在严格模式下执行。

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

实例成员
每次通过 new 调用类标识符时,都会执行类构造函数。在这个函数内部,可以为新创建的实例 ( this )添加自有属性。在构造函数执行完毕后,仍然可以给实例继续添加新成员。

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

不能在类块中给原型添加原始值或对象作为成员数据:

class Person {
	name: 'Jack'
}
// Uncaught SyntaxError: Unexpected token

类方法等同于对象属性,因此可以使用字符串、符号或计算的值作为键:

const symbolKey = Symbol( 'symbolKey' );
class Person {
	stringKey(){
		console.log( 'invoked stringKey' );
	}
	[symbolKey](){
		console.log( 'invoked symbolKey' );
	}
	[ 'computed' + 'Key' ](){
		console.log( 'invoked computedKey' );
	}
}
let p = new Person();
p.stringKey(); // invoked stringKey
p[symbolKey](); // invoked symbolKey
p.comoutedKey(); // invoked computedKey

类定义也支持获取和设置访问器。语法与行为跟普通对象一样:

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

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

静态类成员在类定义中使用 static 关键字作为前缀。在静态成员中,this 引用类自身。

静态类方法非常适合作为实例工厂:

class Person {
	constructor( age ){
		this.age_ = age;
	}
	sayAge(){
		console.log( this.age_ );
	}
	static create(){
		// 使用随机年龄创建并返回一个 Person 实例
		return new Person( Math.floor( Math.random() * 100 ) );
	}
}
console.log( Person.create() ); // Person { age_: ... }

非函数原型和类成员
虽然类定义并不显示支持在原型或类上添加成员数据,但在类定义外部,可以手动添加:

class Person {
	sayName(){
		console.log( '${ Person.greeting } ${ this.name }' );
	}
}
// 在类上定义数据成员
Person.greeting = 'My name is';
// 在原型上定义数据成员
Person.prototype.name = 'Jake';

let p = new Person();
p.sayName(); // My name is Jake

注意 类定义中之所以没有显示支持添加数据成员,是因为在共享目标 (原型和类)上添加可变(可修改)数据成员是一种反模式。一般来说,对象实例应该独自拥有通过 this 引用的数据。

迭代器与生成器方法

继承
ECMAScript 6 新增特性中最出色的一个就是原生支持了类继承机制。虽然类继承机制使用的是新语法,但背后依旧使用的是原型链。

ES6 类支持单继承。使用 extends 关键字,就可以继承任何拥有 [ [ constructor ] ] 和 原型的对象。很大程度上,这意味着不仅可以继承一个类,也可以继承普通的构造函数。

类和原型上定义的方法都会带到派生类。

class Vehicle {
	//原型上的方法
	identifyPrototype( id ){
		console.log( id, this ); // this 实例
	}
	static identifyClass( id ){
		console.log( id, this ); // this Vehicle 类
	}
}

派生类的方法可以通过 super 关键字引用它们的原型。这个关键字只能在派生类中使用,而且仅限于类构造函数、实例方法和静态方法内部。在类构造函数中使用 super 可以调用父类构造函数。

es5 和 es6 使用 new 操作符,会执行如下操作:

  1. 在内存中创建一个一个新对象。
  2. 这个新对象内部的 proto 特性被赋值为构造函数的 prototype属性。
  3. 构造函数内部的 this 被赋值为这个新对象 (即 this 指向新对象)。
  4. 执行构造函数内部的代码(给新对象添加属性)。
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值