前言

据说在编程语言的发展过程中,面向对象语言是为了解决GUI编程的问题而出现的。计算机一开始是用纸带,命令行等来和人进行交互,..不对,是人用纸带跟计算机交互(lll¬ω¬)。而图形界面的出现是一次重大的改进,使普通人很容易就能使用计算机。

我们知道,显示器通常是以60Hz频率刷新的。在显示器的眼中,没有什么按钮,窗口,输入框这些组件的概念,你只需要告诉它在哪个时间,渲染什么样的画面就好了,而我们叫的按钮,窗口等通通都是这一帧画面的一部分。尽管这符合浏览器的习惯,但是这不符合人们的思维习惯。在我们眼里,按钮就是一个物体,它有宽度,高度,还有位置颜色,而不会把它看成是一帧的一部分画面。随着界面的复杂,这种思维上的差异会表现的越来越明显。巧合的是,canvas和GUI编程很像,提供的接口也是一次一次在是刷新画布。下面利用canvas举几个场景来说明这种差异。

场景

  1. 画一个正方形:demo
let cvs = document.querySelector('canvas');
let ctx = cvs.getContext('2d');
ctx.fillStyle = 'red';
ctx.fillRect(10,10,20,20);
  1. 让这个正方形动起来:codepen链接

按显示器的思维,就是擦掉上次的画面,然后在另一个地方重新画一次

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;
}
}
  1. 正方形在移动的时候还会不断缩放

这时你可能会再增加一个长度变量,然后在每一帧的绘制中,改变这个长度变量,来实现这个效果: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])

到这里,我理解的面向对象就算告一段落了,如果有不对的地方,希望各位看官指出。到这里也就算是基础,回到开始那个问题,如果有红桃,草花也在里面运动呢,那就要用到继承了。

从canvas理解面向对象的更多相关文章

  1. 摘抄--全面理解面向对象的 JavaScript

    全面理解面向对象的 JavaScript JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或 ...

  2. Java 雇员管理小练习(理解面向对象编程)

    在学习集合框架的时候,初学者很容易练习到学生管理系统.雇员管理体统等练习题.在学习集合框架之前,基本上Java基本语法都学完了,集合框架也从侧面的检验对前面学习的理解.下面用一个曾经做过的练习题,回顾 ...

  3. 深入全面理解面向对象的 JavaScript

    深入全面理解面向对象的 JavaScript (原著: 曾 滢, 软件工程师, IBM,2013 年 4 月 17 日) JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来 ...

  4. 全面理解面向对象的 JavaScript (share)

     以下分享自:  http://www.ibm.com/developerworks/cn/web/1304_zengyz_jsoo/   简介: JavaScript 函数式脚本语言特性以及其看似随 ...

  5. 全面理解面向对象的 JavaScript

    前言 当今 JavaScript 大行其道,各种应用对其依赖日深.web 程序员已逐渐习惯使用各种优秀的 JavaScript 框架快速开发 Web 应用,从而忽略了对原生 JavaScript 的学 ...

  6. 从一些简单代码实例彻底理解面向对象编程思想|OOP本质是什么?

    从Rob Pike 的 Google+上的一个推看到了一篇叫<Understanding Object Oriented Programming>的文章,我先把这篇文章简述一下,然后再说说 ...

  7. canvas+js+面向对象的圆形封装

    效果: Circle.js /* 1. 封装属性: x, y r, fillStyle strokeStyle opacity 2.render */ function Circle(option) ...

  8. canvas+js+面向对象的矩形封装

    效果: Rect.js /* 1. 封装属性: x, y w , h, fillStyle strokeStyle rotation opacity 2.render */ function Rect ...

  9. java高级特性(1)--理解面向对象思想

    前言: 优秀的代码具备:高性能.可重用.可扩展.易维护.易理解 具体实现: 高性能:合理使用算法,数据结构等等 可重用:封装.继承 可扩展:多态 易维护.易理解:命名规范 + 注解 面向对象是一种思想 ...

随机推荐

  1. 201521123059 《Java程序设计》第四周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 参考资料: 百度脑图 XMind 1.2 使用常规方法总结其他上课内容. 1.多态性就是相同的形态,不同的行为(不同的定义).多态就 ...

  2. Java 课程设计 "Give it up"小游戏设计(个人) 201521123077

    1.团队课程设计博客链接 http://www.cnblogs.com/agts/p/7067948.html 2.个人负责模块或任务说明 个人任务:实现游戏画面的制作,游戏逻辑的编写,以及一些模块与 ...

  3. 多线程面试题系列(8):经典线程同步 信号量Semaphore

    前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数 ...

  4. JVM(三)内存回收(一)

    最近花了相当长一段时间在看Hotspot JVM的GC和内存分配,本节先总结和回顾一下内存回收的相关知识点,内存的分配放到下节再讨论. 一.什么是JVM的GC GC即Garbage Collectio ...

  5. Mybatis第六篇【配置文件和映射文件再解读、占位符、主键生成与获取、Mapper代理】

    配置文件和映射文件再解读 映射文件 在mapper.xml文件中配置很多的sql语句,执行每个sql语句时,封装为MappedStatement对象,mapper.xml以statement为单位管理 ...

  6. Nexus5/6刷 lineageos 过程

    如题,好久没刷机,体验下lineageos 由于之前Xposed官方一直没支持7.x,就没更新 测试三方Xposed正常使用,记录下过程供参考 注意,刷机有风险,刷机前备份,可以使用钛备份 0x01: ...

  7. maven使用私服以后,Missing artifact xxx:xxx:jar:xx的问题

    这里提供的是一种针对特殊情况的的解决方案. 即在你可以顺利使用本地仓库时,在settings.xml中加上私服配置以后出现这样的问题. 解决方案: windows→preferences→Maven→ ...

  8. Ubuntu16.04安装piwik3.0.1

    1.安装PHP环境 sudo apt-get install php7.0-fpm   2.下载piwik3.0.1 https://piwik.org/download/ 下载后解压到/var/ww ...

  9. angular 自定义指令详解 Directive

    在angular中,Directive,自定义指令的学习,可以更好的理解angular指令的原理,当angular的指令不能满足你的需求的时候,嘿嘿,你就可以来看看这篇文章,自定义自己的指令,可以满足 ...

  10. Java 编程思想 Chapter_14 类型信息

    本章内容绕不开一个名词:RTTI(Run-time Type Identification) 运行时期的类型识别 知乎上有人推断作者是从C++中引入这个概念的,反正也无所谓,理解并能串联本章知识才是最 ...