JavaScript面向对象
为什么JavaScript面向对象,因为我最近在写前端,基于canvas写一套控件。
既然是控件那就要封装起来,内部完成渲染,事件处理等功能。
- 类的声明
- 对象创建
- 继承
- 多态
类的声明
废话不多说,直接上代码
export default class View {
/*构造方法*/
constructor(ctx) {
this.ctx = ctx;
}
/*属性*/
width = -1;
height = -1;
/*方法*/
onDraw(canvas) {
console.log('绘制...');
}
setWidth(width) {
this.width = width;
}
setHeight(height) {
this.height = height;
}
getWidth() {
return this.width;
}
getHeight() {
return this.height;
}
}
写到这里,突然有一个想法,把android的那套View写到前端上。
以上是ES6的声明
在ES5中,我们通过构造函数的方式去声明,比如说:
export default function View(ctx) {
this.ctx = ctx;
this.width = -1;
this.height = -1;
this.getHeight = () => {
return this.height;
};
this.getWidth = () => {
return this.width;
};
this.setWidth = (width) => {
this.width = width;
};
this.setHeight = (height) => {
this.height = height;
};
this.onDraw = (canvas) => {
console.log('绘制...');
}
}
但是这种方式声明内部函数,会浪费内存,可以换成原型(prototype)对象的方式来声明函数
export default function View(ctx) {
this.ctx = ctx;
this.width = -1;
this.height = -1;
}
View.prototype.getWidth = () => {
return this.width
};
View.prototype.getHeight = () => {
return this.height
};
View.prototype.setWidth = (width) => {
this.width = width;
};
View.prototype.setHeight = (height) => {
this.height = height;
};
View.prototype.onDraw = (canvas) => {
console.log('绘制...');
};
对象创建
跟java差不多,毕竟叫javascript
let view = new View(this.ctx);
console.log(view);
这样子就有对象了
继承
子类如何继承父类呢?
import View from "./View";
export default class ViewGroup extends View {
layout(l, t, r, b) {
console.log('摆放孩子...');
}
}
我写了一个ViewGroup,继承自View
创建对象:
let viewGroup = new ViewGroup(this.ctx);
viewGroup.onDraw(this.canvas);
然后调用了你类的onDraw方法,当然也可以使用父类的属性
你有java基础的话,一看就懂了,就是这么简单。
调用父类的构造方法
这个熟悉不过了吧,在java是不是用super来调用呀
在javascript里也是这么玩的。
比如说:
import View from "./View";
export default class ViewGroup extends View {
constructor(ctx) {
super(ctx);
}
layout(l, t, r, b) {
console.log('摆放孩子...');
}
}
使用父类的属性
也是很简单的,java怎么用,javascript一样的
比如说:
import View from "./View";
export default class ViewGroup extends View {
constructor(ctx) {
super(ctx);
}
layout(l, t, r, b) {
console.log(super.width);
console.log('摆放孩子...');
}
}
以上是ES6的写法,在ES5里是通过构造函数和原型对象进行模拟继承的关系的,俗称组合继承。
call
方法,类似于java里的反射,invoke
语法:
function.call(thisArgs,args...);
以前面的例子,组合继承:
import View from "./View";
export default function ViewGroup(ctx, name) {
View.call(this, ctx);
this.name = name;
}
ViewGroup.prototype.layout = (l, t, r, b) => {
console.log('摆放孩子...');
};
这样子,调用父类的构造了,并且替换了父类的this,为当前的View的this.
但是方法怎么继承呢?
export default function ViewGroup(ctx, name) {
//方法继承,这样就可以调用View里的方法了
ViewGroup.prototype = new View(ctx);
ViewGroup.prototype.constructor = ViewGroup;
this.name = name;
}
ViewGroup.prototype.layout = (l, t, r, b) => {
console.log('摆放孩子...');
};
我们可以通过原型链的控制,也就是指向父类,这样子就可以掉调用父类中的方法了。
多态
多态给我的感觉就是在javascript中,这语言太弱了,你调用就行,要么有,要么没有。因为没有类型限制呀。
所以,你传入的类中,只要有一样的方法,就可以调用,这不就可以多态了?
比如说:
狗
export default class Dog {
hello() {
console.log('狗:汪汪');
}
}
人类
export default class Human {
hello() {
console.log('人:你好');
}
}
麦克风
export default class Mic {
voice(animal) {
animal.hello();
}
}
调用
let human = new Human();
let dog = new Dog();
let mic = new Mic();
mic.voice(dog);
mic.voice(human);
没有什么类型限制,所以你传进去任意的对象,有这个方法就调用,没有就报错,就是酱紫。