前言
- 在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。
- class 的本质是 function。
- javascript 中,将最底层的类称为基类(BaseClass),子类的父类、父类的父类统称为父类,但是将子类的直属父类称为超类(SuperClass)。
- 可以将类看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。
基础用法
- 用 class 声明类,类名首字母大写,驼峰式命名
- 有些语言的构造函数可以有多个,原生 js 构造函数只能有一个,并且所有类的构造函数写为constructor函数
- 当实例化时执行构造函数 constructor
- 对象的构造函数就是当前的类名
class Box{
a=1;//ES7支持
constructor(a,b){
// 构造函数
// this.a=1;
console.log(a+b);//8
}
play(){
console.log("play");
}
}
// 实例化,当实例化时执行构造函数constructor
let b=new Box(3,5);
console.log(b);
// 对象的构造函数就是当前的类名
console.log(b.constructor===Box);//true
因为 js 中构造函数就是类名,因此我们可以根据对象的构造函数是否是某个类名来判断他是否属于该类;构造函数的 name 属性就是这个类的类名
- constructor 只能用来判断该对象是否属于某个超类
- instanceof 可以来判断该对象是否属于某个父类
var arr=new Array(1,2,3);
//构造函数的name属性就是这个类的类名
console.log(arr.constructor.name);//Array
console.log(arr.constructor===Array);//true
var reg=/a/g;
console.log(reg.constructor===RegExp);//true
var div=document.createElement("div");
console.log(div.constructor===HTMLDivElement);//true
console.log(div.constructor===HTMLElement);//false
console.log(div.constructor===Element);//false
console.log(div instanceof HTMLDivElement);//true
console.log(div instanceof HTMLElement);//true
console.log(div instanceof Element);//true
console.log(div instanceof EventTarget);//true
console.log(div instanceof Node);//true
console.log(div instanceof Object);//true
类的使用
- 通过构造函数实例化的对象,就是这个类的实例对象,因此这个实例对象就具备了类所有属性和方法,就可以调用他自身的方法和属性了
- 类中除了函数中的局部变量就是类中的属性
- 类中的 this 指实例化的对象,谁调用方法,在类的函数中 this 就是那个实例对象
- 因为构造函数默认生成实例化对象,因此不能在构造函数中使用 return 返回其他内容,即构造函数中不允许写return
案例:在页面随机生成大小不一、颜色不同的div
//生成随机颜色
function randomColor(){
var col="#";
for(var i=0;i<6;i++){
col+=Math.floor(Math.random()*16).toString(16);
}
return col;
}
//定义一个叫做Rect的类
class Rect{
elem;
//当实例化生,自动执行constructor函数
constructor(w,h,c){
this.elem=this.createRect(w,h,c);
}
//通过参数创建div
createRect(w,h,c){
let div=document.createElement("div");
Object.assign(div.style,{
width:w+"px",
height:h+"px",
backgroundColor:c
});
return div;
}
appendTo(parent){
parent.appendChild(this.elem);
}
}
for(var i=0;i<10;i++){
var w=Math.floor(Math.random()*50+50);
//实例化Rect
let rect=new Rect(w,w,randomColor());
rect.appendTo(document.body);
}
类的继承
- 使用 extends 用来继承类,继承父类后,必须在构造函数中调用超类的构造函数
- 继承后,子类具有超类的所有属性和方法,也包括超类的静态属性和静态方法
class A{
s=10;
run(){
console.log("aaa");
}
play(){
console.log("play");
}
}
//class B 继承class A
class B extends A{
constructor(){
//继承后,必须在构造函数中调用超类的构造函数
super();
}
run(){
//先执行超类的run方法,再继续执行下面的内容
super.run();
console.log("bbbb");
}
//因为子类的方法与父类的方法相同,因此会覆盖父类的方法
play(){
console.log("A的play方法被覆盖了");
}
}
//实例化class B
let b=new B();
b.run();
类的静态使用
- 使用 static 来声明类的静态属性,不会根据实例化对象的属性改变而改变
- 类的静态属性和方法 可以看作是全局的变量和方法
- 类的静态方法不是针对实例对象来使用的,这个方法中 this 是类名,因此我们通常不在静态方法使用 this,直接使用类名
- 静态方法中是无法调用实例方法的
- 静态方法独是立于其他实例对象的方法
- 静态方法是为了解决某一类问题的方法
- 子类继承超类后,子类具有超类的所有属性和方法,也包括超类的静态属性和静态方法
注意 :static 只有 ES7 以上支持,在低版本浏览器中使用 static 会报错
实例化对象调用不到类中的静态方法
class Box{
static a=1;
a=10;
constructor(){
}
static play(){
console.log("aa");
}
play(){
console.log("ss");
console.log(this.a);
}
}
let b=new Box();
b.play();//ss 10
数组中的 push()、pop()、shift()、slice()…等都是实例对象的方法;from()、isArray()是静态方法。
var arr=[1,2,3,4];
arr.pop();
Array.from(arr);
Array.isArray(arr);
继承后的子类,具有超类所有的静态属性和方法
class A{
static s=10;
static run(){
console.log("aaa");
}
}
//class B 继承class A
class B extends A{
constructor(){
//继承后,必须在构造函数中调用超类的构造函数
super();
}
}
console.log(B.s);// 10
B.run();// aaa
模块化开发
在类的 js 文件中,需要写 export default class 类名,意思是导出的默认类是XX,在页面中引入的时候写 import 类名 from “./js/文件的相对路径”。
export default class Box{
s=10;
constructor(){
//...
}
run(){
console.log("aaa");
}
}
//引入类
import Box from "./js/Box.js"
- 如果类的 js 文件中有多个类,或者在 js 文件中没有写 default,页面中引入类的时候,类名需要用 { } 括起来,也可以一次引入多个类。
- 引入多个类时,类名中间用 逗号 隔开
export class Box{
s=10;
constructor(){
//...
}
run(){
console.log("aaa");
}
}
//引入类
import {Box} from "./js/Box.js";
import {Main,Ball} from "./js/Main.js";