JavaScript面向对象轻松入门之抽象(demo by ES5、ES6、TypeScript)
抽象的概念
狭义的抽象,也就是代码里的抽象,就是把一些相关联的业务逻辑分离成属性和方法(行为),这些属性和方法就可以构成一个对象。
这种抽象是为了把难以理解的代码归纳成与现实世界关联的概念,比如小狗这样一个对象:属性可以归纳出“毛色”、“品种”、“年龄”等等;方法(行为)可以归纳出“叫”、“跑”、“啃骨头”等。
注意:这里的抽象不是指抽象类,抽象类我认为放封装一节讲比较合适。
类的概念和实现
Javascript里创建一个对象有很多种方法,也非常简单,就以小狗这个对象为例:
var dog = {
hairColor: '白色',
breed: '贵宾',
age: 2,
shout: function() {
console.log('汪!汪!汪!'); //这里是你的业务逻辑代码,这里我就简单用这个来代替
},
run: function() {
console.log('吃我灰吧,哈哈!');
},
gnawBone: function() {
console.log('这是本狗最幸福的时候');
}
};
非常便捷,但这时候有个问题:我要创建很多只dog怎么办?每创建一只dog我都var一遍吗?
于是这时候我们就引入了类(class)的概念,类即为类似,具有相同特征的对象的原型,它的作用是创建对象(实例),类本身并不存在内存中,当运行类的代码时,一个对象(实例/instance)就被创建在内存中了,可以简单的理解类为创造对象的工厂。
Javascript(ES5)里没有类(class)这东西,它是通过构造函数来实现类的:
/*类的创建*/
function Dog() {
//构造函数:人们一致协定把构造函数的名字(即类名),首字母大写,以便区分
this.hairColor = '白色';
/*this指向被创造的对象(实例),如果不明白可以简单的理解为给对象(this)赋予hairColor这个属性
*/
this.breed = '贵宾';
this.age = 2;
this.runSpeed = null; //string
/*属性的声明一定要放在构造函数的最顶部;
有的属性可能一开始没有初始值,会在方法里才赋值,但你一定要在构造函数里声明一下
有必要的话再声明一下属性的类型
*/
}
Dog.prototype.shout = function() {
/*我们把方法追加到构造函数的prototype属性,而不是直接在构造函数里用this.shout = function(){};
这样的好处是会让Dog创造的所有对象都共享一个方法,从而节约内存;
一般来说属性在构造函数里赋予,方法在prototype里赋予;
更多prototype的知识就看书去吧,这里不会深讲,作者要保持本章知识的封装性;
*/
console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
//方法里通过this可以访问属性
}
Dog.prototype.run = function() {
this.runSpeed = '10m/s';
console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
}
Dog.prototype.gnawBone = function() {
console.log('这是本狗最幸福的时候');
}
/*对象(实例)的创建与使用*/
var dog1 = new Dog(); //
console.log(dog1.breed); //log: '贵宾'
dog1.shout(); //log: '汪!汪!汪!我是一只2岁的白色贵宾'
var dog2 = new Dog(); //创建多只dog(对象/实例)
var dog3 = new Dog();
/*dog1、dog2、dog3这些对象的属性是各自的,但方法是共享的*/
dog1.hairColor = '黑色'; //修改dog1的属性
console.log(dog1.hairColor); //log: '黑色';dog1属性已被修改;
console.log(dog2.hairColor); //'白色';其它对象不受影响;
console.log(dog3.hairColor); //log: '白色'
console.log(dog1.shout === dog2.shout); //log: true;dog1的shout方法和dog2的是同一个方法;
但新的问题又来了:我想创建一个棕色的泰迪怎么办呢?创建的时候传递参数给类的构造函数就可以解决这问题。
上个案例中说了,类创建的各个对象(实例)的方法的共享的,属性是各自的,但我就是想创建一个共享的属性怎么办呢?比如说我想创建一个instanceNumber属性来记录程序中dog对象(实例)的个数。
这时候就可以给这个Dog类创建一个静态属性,静态属性是属于类的,所以它是不会随对象(实例)的变化而变化,可以用来设置该类的全局变量,全局参数配置等。
下面是新代码:
function Dog(hairColor, breed, age) {
this.hairColor = hairColor; //string,这种依赖参数的属性最好声明下类型或接口;
this.breed = breed; //string
this.age = age; //number
this.runSpeed = null; //string
Dog.instanceNumber++;
}
Dog.instanceNumber = 0; //创建静态属性
Dog.prototype.shout = function() {
console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
}
Dog.prototype.run = function() {
this.runSpeed = '10m/s';
console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
}
Dog.prototype.gnawBone = function() {
console.log('这是本狗最幸福的时候');
}
Dog.prototype.getInstanceNumber = function() { //为访问静态属性封装方法
return Dog.instanceNumber;
}
var dog1 = new Dog('白色', '贵宾', 2);
console.log(Dog.instanceNumber); //log: 1;虽然可以这样访问静态属性,并且还可以修改它,但坚决不推荐这样做
console.log(dog1.getInstanceNumber()); //log: 1;正确的做法!为什么要这样做,在封装一节会详细讲
var dog2 = new Dog('棕色', '泰迪', 1);
console.log(dog1.getInstanceNumber()); //log: 2;
var dog3 = new Dog('黑色', '土狗', 3);
console.log(dog1.getInstanceNumber()); //log: 3;
dog1.shout(); //log: '汪!汪!汪!我是一只2岁的白色贵宾'
dog2.shout(); //log: '汪!汪!汪!我是一只1岁的棕色泰迪'
dog3.shout(); //log: '汪!汪!汪!我是一只3岁的黑色土狗'
接下来是ES6的类的创建方法,这段代码可以直接在Chrome浏览器运行,新手可不用管这部分,包括再下面的TypeScript代码。
class Dog {
constructor(hairColor, breed, age) { //代表这个类的构造函数
this.hairColor = hairColor; //string
this.breed = breed; //string
this.age = age; //number
this.runSpeed = null; //string
Dog.instanceNumber++;
}
shout() {
console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
}
run() {
this.runSpeed = '10m/s';
console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
}
gnawBone() {
console.log('这是本狗最幸福的时候');
}
getInstanceNumber() {
return Dog.instanceNumber;
}
}//ES6类的创建就比较舒服了,class把整个类用{}包裹在一起,写法也比较方便。
Dog.instanceNumber = 0;//遗憾的是ES6里也没有规范静态属性,还是跟ES5一样的用法,据说ES7已有一个静态属性的提案
let dog1 = new Dog('白色', '贵宾', 2);
let dog2 = new Dog('棕色', '泰迪', 1);
let dog3 = new Dog('黑色', '土狗', 3);
dog1.shout(); //log: '汪!汪!汪!我是一只2岁的白色贵宾'
dog2.shout(); //log: '汪!汪!汪!我是一只1岁的棕色泰迪'
dog3.shout(); //log: '汪!汪!汪!我是一只3岁的黑色土狗'
console.log(dog1.getInstanceNumber()); //log: 3;
TypeScript创建对象,TypeScript还有许多有用的特性,但本章不方便介绍更多。
class Dog {
hairColor: string;//class的所有属性必须在顶部全部声明,否则无法通过编译,这让类的创建更加规范;
breed: string;//并且可以声明属性类型,如果给属性赋值的时候类型不正确也无法通过编译,当然,你也可以不声明类型或声明为any任何类型;
age: number;
runSpeed: string;
static instanceNumber: number = 0;//TS静态变量的声明就比较舒服了,在class的{}里面,保证了代码的干净
constructor(hairColor, breed, age) {
this.hairColor = hairColor;
this.breed = breed;
this.age = age;
Dog.instanceNumber++;
}
shout() {
console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
}
run() {
this.runSpeed = '10m/s';
console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
}
gnawBone() {
console.log('这是本狗最幸福的时候');
}
getInstanceNumber() {
return Dog.instanceNumber;
}
}
let dog1 = new Dog('白色', '贵宾', 2);
let dog2 = new Dog('棕色', '泰迪', 1);
let dog3 = new Dog('黑色', '土狗', 3);
dog1.shout();//log: '汪!汪!汪!我是一只2岁的白色贵宾'
dog2.shout();//log: '汪!汪!汪!我是一只1岁的棕色泰迪'
dog3.shout();//log: '汪!汪!汪!我是一只3岁的黑色土狗'
console.log(dog1.getInstanceNumber());//log: 3;
类的抽象
上面的例子是我们明确知道要创建一个对象(实例)dog,但实际开发当中是没有人告诉我们需要创建哪些对象的,领导给我们的只有需求,所以我们要分析需求的业务逻辑,把需求分解成一个个对象。
比如说现在领导给我们一个需求:做一个超市收银系统,分为两种角色:收银员和管理员,收银员可以查询物品信息、统计价格、录入账单信息、打印小票,管理员可以查看账单信息、统计账单信息。
注意需求中的名词:收银员、管理员、物品信息、账单、小票,这些就是天然的对象,这是最初步的抽象。
让我们再注意动词:查询、统计、录入、打印,我们是不是也可以抽象成对象?查询器?统计器?
然后我们开始coding吧,不要纠结自己的抽象是否完美,作者很赞同Facebook的一句标语:Done is better than perfect(比完美更重要的是完成).
当某个对象的代码不断膨胀,慢慢超出控制的时候(作者自己的的标准是一个对象尽量不超过300行代码),这时候你就得考虑更深层次的抽象了,查找这个对象里代码比较多的属性、方法、然后抽象成另一个对象,把新对象作为原先对象的成员(属性)。
function Dog(){
this._tail = new Tail();//把尾巴tail抽象成另一个对象,作为dog的一个属性;
}
当然,你成了老司机后可以一开始就把一个对象再抽象出许多成员对象,随你喜欢。
后话
如果你喜欢作者的文章,记得收藏,你的点赞是对作者最大的鼓励;
作者会尽量每周更新一章,下一章是讲封装;
大家有什么疑问可以留言或私信作者,作者尽量第一时间回复大家;
如果老司机们觉得那里可以有不恰当的,或可以表达的更好的,欢迎指出来,作者会尽快修正、完善。
JavaScript面向对象轻松入门之抽象(demo by ES5、ES6、TypeScript)的更多相关文章
- JavaScript面向对象轻松入门之封装(demo by ES5、ES6、TypeScript)
本章默认大家已经看过作者的前一篇文章 <JavaScript面向对象轻松入门之抽象> 为什么要封装? 封装(Encapsulation)就是把对象的内部属性和方法隐藏起来,外部代码访问该对 ...
- JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)
写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向 ...
- JavaScript面向对象轻松入门之继承(demo by ES5、ES6)
继承是面向对象很重要的一个概念,分为接口继承和实现继承,接口继承即为继承某个对象的方法,实现继承即为继承某个对象的属性.JavvaScript通过原型链来实现接口继承.call()或apply()来实 ...
- JavaScript面向对象轻松入门之多态(demo by ES5、ES6、TypeScript)
多态(Polymorphism)按字面的意思就是"多种状态",同样的行为(方法)在不同对象上有不同的状态. 在OOP中很多地方都要用到多态的特性,比如同样是点击鼠标右键,点击快捷方 ...
- JavaScript面向对象轻松入门之综合
javascrpit面向对象之综合 这一章是对前几章的一个总结,通过一个案例来综合认识javascript面向对象的基本用法 需求: 几乎所有的web应用都需要保存数据一些到本地,那么我们就来 ...
- JavaScript面向对象编程入门
来源极客网 function Person() { var _this = {} //创建一个空的对象,接着我们利用这个"空的对象"承载Person的属性和方法 _this.say ...
- Swift轻松入门——基本语法介绍和详细地Demo讲解(利用WebView打开百度、新浪等网页)
转载请务必注明出处(all copyright reserved by iOSGeek) 本文主要分为两个部分,第一部分介绍Swift的基本语法,第二部分讲解一个利用WebView来打开百度.sina ...
- 风趣的JavaScript面向对象入门课程一
在我们程序猿界一直流传这这么一个joke,没女票我们可以new一个.没房子没票子没车子我们同样new一个!当然这听着更像是一种自嘲,毕竟我们程序猿都爱自嘲,哈哈,废话不多说,今天就由我带着你们来入Ja ...
- 《挑战30天C++入门极限》理解C++面向对象程序设计中的抽象理论
理解C++面向对象程序设计中的抽象理论 很多书在一开始就开始学习josephus问题,为了让大家前面学起来较为容易我把前面涉及到此问题的地方都故意去掉了,现在我们已经学习过了结构体和类,所以放 ...
随机推荐
- NodeJs之fs的读写删移监
NodeJs版本:4.4.4 fs 文件系统模块是一个封装了标准的 POSIX 文件 I/O 操作的集合.Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本. 图片的复制与粘贴 创建 ...
- Mongo汇总问题
1. 数据 /* 5 */ { "_id" : ObjectId("5902f7ca2b3fe442d60a0946"), "code" : ...
- Integer浅谈
别BB,亮代码. 结果: 结果分析: 1.true 相信大家对第一个的比较结果应该不意外,只是单纯的数值比较 2.true 这个和第三个结果一比较起来就感觉迷惑了,明明两个都是同样的赋值方式,为什么一 ...
- jquery.uploadifive 解决上传限制图片或文件大小
dotNet疯狂之路No.28 今天很残酷,明天更残酷,后天很美好,但是绝大部分人是死在明天晚上,只有那些真正的英雄才能见到后天的太阳. We're here to put a dent in t ...
- MapControl Application 添加自定义的工具条
现在想用二次开发做一些东西,然后需要自定义的工具条,但是如何向MapControl Application 添加自定义的工具条呢,经过多次试验后,终于找到了相应的方法(左图是添加自定义的工具条之前,右 ...
- ZooKeeper 入门
0 介绍 官网:http://zookeeper.apache.org/ ZooKeeper是Hadoop的正式子项目,它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护.名字服务.分 ...
- React入门---属性(state)-7
state------>虚拟dom------>dom 这个过程是自动的,不需要触发其他事件来调用它. state中文理解:页面状态的的一个值,可以存储很多东西. 学习state的使用: ...
- 解决window.navigator.geolocation.getCurrentPosition在IOS10系统中无法进行地理定位问题
昨天接到用户通知说在点击"看场地"时无法获取地理位置信息. 在接到通知时,首先想到的是排查机型问题.由于客户多为IOS用户,所以最先看的是在安卓是有没有此问题的发生,调查结果为安卓 ...
- 基于python的爬虫(一)
抓取网页 python核心库 urllib2 实现对静态网页的抓取,不得不说,"人生苦短,我用python"这句话还是有道理的,要是用java来写,这估计得20行代码 (对不住了博 ...
- 【JAVAWEB学习笔记】28_jqueryAjax:json数据结构、jquery的ajax操作和表单校验插件
Ajax-jqueryAjax 今天内容: 1.json数据结构(重点) 2.jquery的ajax操作(重点) 3.jquery的插件使用 一.json数据结构 1.什么是json JSON(J ...