1.类的声明
最早期的JavaScript中没有类的概念,最相近的思路是创建一个自定义的类型:首先创建一个构造函数,然后定义另一个方法并赋值给构造函数的原型。
<script>
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
var person = new Person('galaxy');
person.sayName()
</script>
这段代码中Person是一个构造函数,其执行后创建一个名为name的属性,给Person的原型添加了一个sayName的方法,所以Person对象的所有实例都将共享这个方法。
以上这种写法跟面向对象语言差异比较大,ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
<script>
class Person{
constructor(name){
// 等价于Person构造函数
this.name = name;
}
// 等价于Person.prototype.sayName
sayName(){
console.log(this.name);
}
}
let person = new Person('galaxy');
person.sayName();
console.log(typeof Person);
</script>
这里通过 constructor方法名来定义构造函数,这里typeof Person最终返回的结果是‘function’,所以Person声明实际上创建了一个具有构造函数方法行为的函数。实例中的sayName方法实际上是Person.prototype上的一个方法。
2.类与自定义类型
差异
- 函数声明可以提升,而类声明与let声明类似,不能被提升
- 在自定义类型中,需要通过Object.defineProperty()方法手工指定某个方法不可枚举,但是在类中,所有的方法都是不可以枚举的。
- 每个类都有一个名为[[Construct]]的内部方法,通过关键字new调用那些不含[[Construct]]的方法会导致程序抛出错误
3.常量类名
类的名称只在类中为常量,所以不能在类的方法中修改类名,但是可以在外部修改
<script>
class Foo{
constructor(){
Foo = 'bar' //执行报错
}
}
Foo = 'bar'; //修改成功
</script>
4.类表达式
类和函数都存在两种形式,声明形式和表达式形式。
<script>
let Person = class{
//等价于Person构造函数
constructor(name){
this.name = name;
}
sayName(){
console.log(this.name);
}
}
let person = new Person('galaxy');
person.sayName();
</script>
5.命名类表达式
类和函数一样都可以定义为命名表达式
<script>
let Person = class Person1{
//等价于Person构造函数
constructor(name){
this.name = name;
}
sayName(){
console.log(this.name);
}
}
console.log(typeof Person) //function
console.log(typeof Person1) // undefined
</script>
类表达式被命名为Person1,由于标识符Person1只存在于类定义中,因此只能被用在类内部,比如sayName这样的方法中。这个类的名字是Person而不是Person1,Person1只在Class的内部代码可用,指代当前类。
6.静态成员
在ECMAScript5中,直接将方法添加到构造函数中来模拟静态成员
<script>
function Person(name){
this.name = name;
}
// 静态方法
Person.create = function(name){
return new Person(name);
}
// 实例方法
Person.prototype.sayName = function(){
console.log(this.name);
}
var person = Person.create('galaxy');
person.sayName();
</script>
ES6中
<script>
class Person{
constructor(name){
this.name = name;
}
static sayName(){
console.log(this.name);
}
}
let person = new Person()
person.sayName(); //typeError: person.sayName is not a function
</script>
类的sayName方法前有static关键字,表明该方法是一个静态方法,可以直接在Person类上调用(Person.sayName()),而不是在Person类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。
不可在实例中访问静态成员,必须要直接在类中访问静态成员
7.类的继承
ECMAScript5中中实现继承
<script>
function Rectangle(length,width){
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function(){
return this.length * this.width
}
function Square(length){
Rectangle.call(this,length,length);
}
Square.prototype = new Rectangle();
Square.prototype.constructor = Square;
const square = new Square(3);
console.log(square.getArea(3))
</script>
ES6中 Class之间可以通过extends关键字实现继承
<script>
class Rectangle{
constructor(length,width){
this.length = length;
this.width = width;
}
getArea(){
return this.length * this.width
}
}
class Square extends Rectangle{
constructor(length){
// 等价于Rectangle.call(this,length,length)
super(length,length);
}
}
var square = new Square(3);
console.log(square.getArea())
</script>
实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
在子类的构造函数中,只有调用super之后,才可以使用this关键字。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。
8.子类对父类方法的重写
<script>
class Phone{
// 构造方法
constructor(brand,price){
this.brand = brand;
this.price = price;
}
// 父类的成员属性
call(){
console.log('我可以打电话')
}
}
class SmartPhone extends Phone{
// 构造方法
constructor(brand,price,color,size){
super(brand,price); // Phone.call
this.color = color;
this.size =size;
}
photo(){
console.log('拍照')
}
playGame(){
console.log('玩游戏')
}
call(){
console.log('wokeyishi')
}
}
const xiaomi = new SmartPhone('xiaomi',7999,'red','4.7');
console.log(xiaomi);
xiaomi.call();
</script>
9.Class的取值函数(getter)和存值函数(setter)
Class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数.
<script>
// get set
class Phone{
// 获取属性
get price(){
console.log('价格属性被读取了');
return 'ilive'
}
// 设置属性
set price(newVal){
console.log('价格属性被修改了')
}
}
let s = new Phone();
// console.log(s.price)
s.price = 'free';
console.log(s.price)
</script>