以一个简单的废话生成器为例子
网页结构很简单如图,我们想自己可以在文本框中输入文字,点击一级废话和二级废话,来生成一堆废话。
1.class和new
我们创建一个废话生成器,整合为一个类来实现功能。注意我们写的class首字母小写,类名首字母大写,其实class和构造函数类似,类型都为function,接下来我们生成一个废话实例(注意实例要写在定义类后面,因为class没有声明提升)如下所示。
class Bullshit {
}
const bullshit = new Bullshit();
2.constructor
生成实例后明显是个空实例,因为class里没有属性,所以我们按照惯例给class添加属性,这些属性是每次生成实例都会各自添加的,也就是说我们要让每个实例都有各自特有的属性,但是都共享同一套代码,于是我们就要用到constructor了,constructor是class里的一个方法,每次new的时候就会触发这个constructor,这就很符合我们生成构造函数的情形,于是我们先确定好参数,text为废话,color为废话的颜色,所以我们在实例new的时候传入两个参数。现在有了属性,我们要实现功能,还应该有对应的方法。
class Bullshit {
constructor(text, color) {
this.text = text;
this.color = color;
}
}
const bullshit = new Bullshit('我知道', '#00a1d6');
3.自定义方法
在class里创建方法是不需要加function关键字的,show()方法用来在p标签里展示废话并修改字体颜色,因此我们需要给一级废话按钮添加点击事件,并且把刚刚创建的废话实例放进触发事件函数里面,然后我们用废话实例执行show()方法。
class Bullshit {
constructor(text, color) {
this.text = text;
this.color = color;
}
show() {
p.innerHTML = this.text + input.value;
p.style.color = this.color;
}
}
button_1st.addEventListener('click', () => {
const bullshit = new Bullshit('我知道', '#00a1d6');
bullshit.show();
})
我们点击一级废话按钮,就可以在下方p标签生成废话,同时字体颜色改变,这样一级废话功能基本完成。
4.extends和super
接下来我们来写二级废话的功能实现,但是我们不想把代码重新写一遍,有没有什么办法呢,class里面有个extends关键字可以用来继承,那么我们现在就来创建一个废话子类继承刚刚的废话父类(也就是一级废话功能),并且给二级废话按钮添加点击事件,像下面这个样子。
class Bullshit {
constructor(text, color) {
this.text = text;
this.color = color;
}
show() {
p.innerHTML = this.text + input.value;
p.style.color = this.color;
}
}
class Son_of_Bullshit extends Bullshit {
}
button_1st.addEventListener('click', () => {
const bullshit = new Bullshit('我知道', '#00a1d6');
bullshit.show();
})
button_2nd.addEventListener('click', () => {
const son_of_bullshit = new Son_of_Bullshit('你知道', '#f85b88');
son_of_bullshit.show();
})
另外我们还希望二级废话按钮可以改变字体大小,所以我们要给二级废话增加一个属性,那就是生成废话的时候可以改变字体大小,于是我们先传入一个实参’30px’,然后我们添加一个参数fontSize表示字体,并且把实参赋值给实例。但是这样代码可以正确执行吗?
class Bullshit {
constructor(text, color) {
this.text = text;
this.color = color;
}
show() {
p.innerHTML = this.text + input.value;
p.style.color = this.color;
}
}
class Son_of_Bullshit extends Bullshit {
constructor(fontSize) {
this.text = text;
this.color = color;
this.fontsize = fontSize;
}
}
button_1st.addEventListener('click', () => {
const bullshit = new Bullshit('我知道', '#00a1d6');
bullshit.show();
})
button_2nd.addEventListener('click', () => {
const son_of_bullshit = new Son_of_Bullshit('你知道', '#f85b88', '30px');
son_of_bullshit.show();
})
答案是不能,虽然我们用extends进行了继承,但并不代表我们不能改变子类,所以其实我们在子类写constructor方法的时候,实际上就是在覆盖原来父类的constructor方法。当然,如果你想直接全部重新父类属性方法可以吗,毕竟只是多了一个fontSize,那么这样可以执行吗?
答案依然是否定的。如果在子类中写了constructor就必须调用super(),问题就在于这里的this,我们父类里有this,子类里面也有this,父类和子类的this都是绑定各自实例的,我们子类既然这样子继承了父类的东西,那么我们如果照搬过来肯定是很混乱的,因此我们需要用super来初始化this。总之,在子类constructor里写this之前一定要写super,前super,后this。
不仅可以改写父类的属性,我们也可以改写父类的方法,在下面代码块区域这里,我们将父类的show方法改写为用子类废话实例和当前输出内容相加,这样二级废话按钮就可以不断点击生成废话。
class Son_of_Bullshit extends Bullshit {
constructor(text, color, fontSize) {
super(text, color);
this.fontSize = fontSize;
}
show() {
p.innerHTML = this.text + p.innerHTML;
p.style.color = this.color;
p.style.fontSize = this.fontSize;
}
}
5.static
另外有一些我们不需要也不想要创建新的实例的部分,我们一般会用static关键字来创建一个方法,这里就以一个温馨提示为例子,我们创建了welcome_tipos这个方法,然后在里面返回了一段温馨提示。如果我们想调用这个静态方法,我们可以在在创建一个静态方法welcome,并且把welcome_tips里返回的内容输出到p标签里面。那么请问大家这里的this有毛病吗?
class Bullshit {
static welcome_tips() {
return '温馨提示:您这是在说废话';
}
static welcome() {
p.innerHTML = this.welcome_tips();
}
......
p.addEventListener('click', () => {
Bullshit.welcome();
})
}
没毛病,因为在一个静态方法里调用另一个静态方法是可以用this的,这里的this并不是绑定实例的,这里的this是绑定类本身的,因为静态方法是需要类调用,而不是实例去调用。这里我不想再增加按钮了,于是直接在p标签上添加点击事件,并且在事件函数里只用类调用静态方法welcome,可千万不要用实例去调用静态方法,不然会报错的。
6.setter和getter
现在我们的废话生成器已经越来越完善了,可是我觉得还不够废话,想再额外设置一些废话,既然是设置类的功能,我们就可以使用setter,javascript对象中也是可以使用getter和setter的,class也恰好把这两个功能给封装起来。
首先我们设置setter,也就是set加上标识符,而且我们还添加一个参数,然后再setter里面把参数赋值给实例的value属性,并且把value属性值加载原来的p标签内容里面,最后我们在鼠标点击事件里面进行属性设置即可。这里要注意,setter其实是访问器属性,是一个有特殊功能的属性。
class Bullshit {
......
set extra(value) {
this.value = value;
p.innerHTML += this.value; //把value属性值加在原来的p标签内容里面
}
}
......
button_1st.addEventListener('click', () => {
const bullshit = new Bullshit('我知道', '#00a1d6');
bullshit.show();
bullshit.extra = '儿'; //在点击事件里进行属性设置
})
如果废话太多时候,用户可能就不知道哪里是废话这就需要用到getter了,我定义的名字是和setter一样的,因为getter和setter是一对的,接着我在getter里返回内容,并且在实例中输出getter内容,这里同样要注意不要再extra后面加上括号,因为这是属性。
class Bullshit {
......
get extra() {
return `这些是废话:${this.text}, ${this.value}`;
}
}
.......
button_1st.addEventListener('click', () => {
const bullshit = new Bullshit('我知道', '#00a1d6');
bullshit.show();
bullshit.extra = '儿'; //在点击事件里进行属性设置
console.log(bullshit.extra);
})
我们点击按钮,可以看到控制台输出相应内容,代码中的extra被定义为getter和setter之后,同一个名字既可以赋值,也可以输出内容。
这些就是ES6中class的核心知识了。