Class类

ES6提供了更接近传统语言的类的写法,引入了 Class(类) 这个概念,作为对象的模板。通过 Class 关键字,可以定义类;通过类,可以实例化对象。基本上,ES6的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

知识点:

1)class 声明类;

2)constructor 定义构造函数初始化

3)extends 继承父类

4)super 调用父级的构造方法

5)static 定义静态方法和属性

6)父类方法可以重写


通过构造函数实例化对象

function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log('i can make a phone call.');
}
let hw = new Phone('huawei',3999);
console.log(hw);
hw.call();

Javascript(笔记41) - ES6特性 - Class类_ES6

创建Class类

constructor 固定用法,自动执行;当然,这个也不是必须要写的;

当使用 “new + 类名” 实例化对象时,时会自动执行 constructor 方法;

class Phone {
constructor(brand, price) { // 固定用法,只能写 constructor
this.brand = brand;
this.price = price;
}

call() { // 只能写 fn(){}
console.log('i can make a phone call.');
}
}
let xiaomi = new Phone("xiaomi", 2999);
console.log(xiaomi);
xiaomi.call();

Javascript(笔记41) - ES6特性 - Class类_类的静态属性_02

这和用构造函数实例化的对象,几乎一样;


Class静态成员

先看下ES5的实例:

function Phone(){}
Phone.name = "phone";
Phone.call = function(){
console.log('i can make a phone call.');
}

给构造函数本身添加的属性和方法,是不能被实例化对象继承的;

let onePlus = new Phone();
console.log(onePlus.name); // undefined
onlPlus.call(); // 报错

只能把属性和方法定义在构造函数的原型上才可以被实例化对象继承;

function Phone(){};
Phone.prototype.size = '5.5inch'; // 定义在原型上的属性
Phone.prototype.play = function(){ // 定义在原型上的方法
console.log('i can play games.');
}

let onePlus = new Phone();
console.log(onePlus.size); // 5.5inch
onePlus.play(); // i can play games.

构造函数的属性是属于构造函数本身的,我们管这个叫静态属性

放在面向对象里面,这种属性是属于类的,而不属于实例对象的;

声明类的静态属性,要使用 static 关键字;

class Phone{
// 静态属性
static name = 'mobile phone';
static call(){
console.log('i can make a phone call.');
}
}

let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name); // mobile phone

nokia.call(); // 报错: nokia.call is not a function
Phone.call(); // i can make a phone call.

这实例就能清楚的区分,静态属性仅有类本身可用,实例化的对象不能用;


ES5构造函数继承

回顾ES5 构造函数实现继承;

function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){ // 父级原型方法 call
console.log('i can make a phone call.');
}

// 智能手机
function SmartPhone(brand,price,color,size){
Phone.call(this,brand,price); // call 过来
this.color =color;
this.size = size;
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone(); // 定义父级继承
SmartPhone.prototype.constructor = SmartPhone; // 矫正 constructor

// 声明子类的方法
SmartPhone.prototype.photo = function(){ // 定义子级方法
console.log('i can take pictures.');
}
SmartPhone.prototype.playGame = function(){
console.log('i can play games.');
}

// 实例化对象
const chuizi = new SmartPhone('Chuizi',2999,'blank','5.5inch');
console.log(chuizi); // 所有属性都有;
chuizi.call(); // 调用父级原型方法;
chuizi.photo(); // 调用自己原型的方法;
chuizi.playGame();

Javascript(笔记41) - ES6特性 - Class类_类的静态属性_03

输出结果,没有问题;


Class类继承

class类继承的结果,跟构造函数继承的效果一样;

但 class 类里的继承父类,使用 extends super 关键字;

// 先写父类
class Phone {
// 构造父类
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 父类方法
call() {
console.log('i can make a phone call.');
}
}

// 再写子类
class SmartPhone extends Phone { // 使用 extends 关键字来继承父类
// 构造子类属性
constructor(brand, price, color, size) {
super(brand, price); // 相当于 Phone.call(this,brand,price);
this.color = color;
this.size = size;
}
// 子类方法
photo() {
console.log('i can take pictures.');
}
playGames() {
console.log('i can play games.');
}
}

let redMi = new SmartPhone('xiaomi', 899, 'blank', '4.7inch');
console.log(redMi);
console.log(`i using ${redMi.brand} phone, color is ${redMi.color}.`); // 字符串模板
redMi.call(); // 调用父类方法;
redMi.photo(); // 调用子类方法;
redMi.playGames();

Javascript(笔记41) - ES6特性 - Class类_类的静态属性_04

属性和方法跟构造函数实例化的对象几乎一样;

使用 Class 类写出来的继承,相对简洁、易读;


子类对父类方法的重写

在子类里,把父类的同名方式覆盖就是重写,而且子类不能调用父类的同名方法

call(){        // 在子类中,用父类的同名方法重写一个方法
console.log('i can video call.');
}

redMi.call(); // i can video call.

Class类中的 get 和 set 设置

当对类里一个属性进行获取或设置时,可以使用 get 和 set 

class Phone{
get price(){
console.log('价格属性被读取了');
return '价格是: 1299元';
}
set price(newVal){
console.log('价格属性被修改了');
}
}

let s = new Phone();
console.log(s.price); // 价格属性被读取了, 价格是: 1299元
s.price = 1099; // 价格属性被修改了

get 通常会对对象的动态属性进行封装;如,属性是变化的,求总数、平均数等;

set 可以添加控制和判断,如,设置的值是不是正确的啊,成功就赋值,失败就放弃等;