据说在编程语言的发展过程中,面向对象语言是为了解决GUI编程的问题而出现的。计算机一开始是用纸带,命令行等来和人进行交互,..不对,是人用纸带跟计算机交互(lll¬ω¬)。而图形界面的出现是一次重大的改进,使普通人很容易就能使用计算机。
我们知道,显示器通常是以60Hz频率刷新的。在显示器的眼中,没有什么按钮,窗口,输入框这些组件的概念,你只需要告诉它在哪个时间,渲染什么样的画面就好了,而我们叫的按钮,窗口等通通都是这一帧画面的一部分。尽管这符合浏览器的习惯,但是这不符合人们的思维习惯。在我们眼里,按钮就是一个物体,它有宽度,高度,还有位置颜色,而不会把它看成是一帧的一部分画面。随着界面的复杂,这种思维上的差异会表现的越来越明显。巧合的是,canvas和GUI编程很像,提供的接口也是一次一次在是刷新画布。下面利用canvas举几个场景来说明这种差异。
- let cvs = document.querySelector('canvas');
- let ctx = cvs.getContext('2d');
- ctx.fillStyle = 'red';
- ctx.fillRect(10, 10, 20, 20);
按显示器的思维,就是擦掉上次的画面,然后在另一个地方重新画一次
- let x = 0,y = 0,speed={x:1,y:1};
- function draw(){
- ctx.clearRect(0,0,400,400);
- ctx.fillRect(x,y,20,20);
- x+=speed.x;
- y+=speed.y;
- if(x>400 || x<0){
- speed.x = -speed.x;
- speed.y = -speed.y;
- }
- }
这时你可能会再增加一个长度变量,然后在每一帧的绘制中,改变这个长度变量,来实现这个效果:demo
- let x = 0,y = 0,len = 10;speed={x:1,y:1,scale:1};
- function draw(){
- ctx.clearRect(0,0,400,400);
- ctx.fillRect(x,y,len,len);
- x+=speed.x;
- y+=speed.y;
- len += speed.scale;
- if(x>400 || x<0){
- speed.x = -speed.x;
- }
- if(y>400 || y<0){
- speed.y = -speed.y;
- }
- if(len>20 || len<10){
- speed.scale = -speed.scale;
- }
- }
我们将方块的位置,大小,颜色这些称为方块的状态。通过三个例子可以发现,随着方块的状态越来越多,比方说可以发射子弹。或者除了方块之外,还有草花,红桃也在来回移动,程序会变得越来越难于管理。这时候就需要面向对象了。
按照我们的思考方式,上面的场景就是一个方块的位置和大小在发生变化,所以有以下代码:
- function Block(x, y, len, color,speed){
- this.x = x || 0;
- this.y = y || 0;
- this.len = len || 10;
- this.color = color || 'red';
- this.speed = speed ||{
- x:1,y:1,scale:1
- }
- }
- let redBlock = new Block(0,0,10,'red');
这样,就把一个方块相关的属性放到一个对象里,而不像上面的一堆变量,毫无结构。同时,还能很方便的new 出大小,位置,颜色各不相同的方块。
另一个要注意的地方是speed这个属性,一开始写的时候,我计划是将speed作为函数move的参数,但是这样是不行的,原因是,函数move不会保留方块的移动状态,因此要作为方块的属性存放。
下面我们让方块动起来,我们把方块会动当成是方块的一个行为的话,就有下面的代码:
- Block.prototype.move = function(speed){
- this.speed = speed || {
- x:1,y:1,scale:1
- }
- this.x += this.speed.x;
- this.y += this.speed.y;
- this.len += this.speed.scale;
- if(this.x>400 || this.x<0){
- this.speed.x = -this.speed.x;
- }
- if(this.y>400 || this.y<0){
- this.speed.y = -this.speed.y;
- }
- if(this.len>20 || this.len<10){
- this.speed.scale = -this.speed.scale;
- }
- }
于是我们就有了一个会动的方块,最后一步是渲染,不妨把这个行为作为Block这个类的一个静态方法:
- Block.render = function(block) {
- let cvs = document.querySelector('canvas');
- let ctx = cvs.getContext('2d');
- setInterval(function() {
- ctx.clearRect(0, 0, 400, 400);
- ctx.fillStyle = block.color;
- ctx.fillRect(block.x, block.y, block.len, block.len);
- block.move();
- },
- 100)
- }
渲染多个方块也容易:
- Block.renderMany = function(blocks) {
- let cvs = document.querySelector('canvas');
- let ctx = cvs.getContext('2d');
- setInterval(function() {
- ctx.clearRect(0, 0, 400, 400);
- for (let block of blocks) {
- ctx.fillStyle = block.color;
- ctx.fillRect(block.x, block.y, block.len, block.len);
- block.move();
- }
- },
- 100)
- }
渲染方块:demo
- let redBlock = new Block(0,0,10,'red');
- let blueBlock = new Block(200,200,20,'blue',{x:-1,y:1,scale:2})
- // Block.render(redBlock);
- Block.renderMany([redBlock,blueBlock])
到这里,我理解的面向对象就算告一段落了,如果有不对的地方,希望各位看官指出。到这里也就算是基础,回到开始那个问题,如果有红桃,草花也在里面运动呢,那就要用到继承了。
来源: http://www.cnblogs.com/imgss/p/7712103.html