JavaScript面向对象轻松入门之抽象(demo by ES5、ES6、TypeScript)

   2023-02-09 学习力0
核心提示:抽象的概念  狭义的抽象,也就是代码里的抽象,就是把一些相关联的业务逻辑分离成属性和方法(行为),这些属性和方法就可以构成一个对象。  这种抽象是为了把难以理解的代码归纳成与现实世界关联的概念,比如小狗这样一个对象:属性可以归纳出“毛色”、

抽象的概念

  狭义的抽象,也就是代码里的抽象,就是把一些相关联的业务逻辑分离成属性和方法(行为),这些属性和方法就可以构成一个对象。

  这种抽象是为了把难以理解的代码归纳成与现实世界关联的概念,比如小狗这样一个对象:属性可以归纳出“毛色”、“品种”、“年龄”等等;方法(行为)可以归纳出“叫”、“跑”、“啃骨头”等。

  注意:这里的抽象不是指抽象类,抽象类我认为放封装一节讲比较合适。

类的概念和实现

  Javascript里创建一个对象有很多种方法,也非常简单,就以小狗这个对象为例:

 1 var dog = {
 2     hairColor: '白色',
 3     breed: '贵宾',
 4     age: 2,
 5     shout: function() {
 6         console.log('汪!汪!汪!'); //这里是你的业务逻辑代码,这里我就简单用这个来代替
 7     },
 8     run: function() {
 9         console.log('吃我灰吧,哈哈!');
10     },
11     gnawBone: function() {
12         console.log('这是本狗最幸福的时候');
13     }
14 };

  非常便捷,但这时候有个问题:我要创建很多只dog怎么办?每创建一只dog我都var一遍吗?

  于是这时候我们就引入了类(class)的概念,类即为类似,具有相同特征的对象的原型,它的作用是创建对象(实例),类本身并不存在内存中,当运行类的代码时,一个对象(实例/instance)就被创建在内存中了,可以简单的理解类为创造对象的工厂。

  JavascriptES5)里没有类(class)这东西,它是通过构造函数来实现类的:

 

 1 /*类的创建*/
 2 function Dog() {
 3     //构造函数:人们一致协定把构造函数的名字(即类名),首字母大写,以便区分
 4     this.hairColor = '白色';
 5     /*this指向被创造的对象(实例),如果不明白可以简单的理解为给对象(this)赋予hairColor这个属性
 6      */
 7     this.breed = '贵宾';
 8     this.age = 2;
 9     this.runSpeed = null; //string
10     /*属性的声明一定要放在构造函数的最顶部;
11     有的属性可能一开始没有初始值,会在方法里才赋值,但你一定要在构造函数里声明一下
12     有必要的话再声明一下属性的类型
13     */
14 }
15 Dog.prototype.shout = function() {
16     /*我们把方法追加到构造函数的prototype属性,而不是直接在构造函数里用this.shout = function(){};
17     这样的好处是会让Dog创造的所有对象都共享一个方法,从而节约内存;
18     一般来说属性在构造函数里赋予,方法在prototype里赋予;
19     更多prototype的知识就看书去吧,这里不会深讲,作者要保持本章知识的封装性;
20     */
21     console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
22     //方法里通过this可以访问属性
23 }
24 Dog.prototype.run = function() {
25     this.runSpeed = '10m/s';
26     console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
27 }
28 Dog.prototype.gnawBone = function() {
29     console.log('这是本狗最幸福的时候');
30 }
31 /*对象(实例)的创建与使用*/
32 var dog1 = new Dog(); //
33 console.log(dog1.breed); //log: '贵宾'
34 dog1.shout(); //log: '汪!汪!汪!我是一只2岁的白色贵宾'
35 var dog2 = new Dog(); //创建多只dog(对象/实例)
36 var dog3 = new Dog();
37 /*dog1、dog2、dog3这些对象的属性是各自的,但方法是共享的*/
38 dog1.hairColor = '黑色'; //修改dog1的属性
39 console.log(dog1.hairColor); //log: '黑色';dog1属性已被修改;
40 console.log(dog2.hairColor); //'白色';其它对象不受影响;
41 console.log(dog3.hairColor); //log: '白色'
42 console.log(dog1.shout === dog2.shout); //log: true;dog1的shout方法和dog2的是同一个方法;

 

  但新的问题又来了:我想创建一个棕色的泰迪怎么办呢?创建的时候传递参数给类的构造函数就可以解决这问题。
  上个案例中说了,类创建的各个对象(实例)的方法的共享的,属性是各自的,但我就是想创建一个共享的属性怎么办呢?比如说我想创建一个instanceNumber属性来记录程序中dog对象(实例)的个数。

  这时候就可以给这个Dog类创建一个静态属性,静态属性是属于类的,所以它是不会随对象(实例)的变化而变化,可以用来设置该类的全局变量,全局参数配置等。

  下面是新代码:

 1 function Dog(hairColor, breed, age) {
 2     this.hairColor = hairColor; //string,这种依赖参数的属性最好声明下类型或接口;
 3     this.breed = breed; //string
 4     this.age = age; //number
 5     this.runSpeed = null; //string
 6     Dog.instanceNumber++;
 7 }
 8 Dog.instanceNumber = 0; //创建静态属性
 9 Dog.prototype.shout = function() {
10     console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
11 }
12 Dog.prototype.run = function() {
13     this.runSpeed = '10m/s';
14     console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
15 }
16 Dog.prototype.gnawBone = function() {
17     console.log('这是本狗最幸福的时候');
18 }
19 Dog.prototype.getInstanceNumber = function() { //为访问静态属性封装方法
20     return Dog.instanceNumber;
21 }
22 var dog1 = new Dog('白色', '贵宾', 2);
23 console.log(Dog.instanceNumber); //log: 1;虽然可以这样访问静态属性,并且还可以修改它,但坚决不推荐这样做
24 console.log(dog1.getInstanceNumber()); //log: 1;正确的做法!为什么要这样做,在封装一节会详细讲
25 var dog2 = new Dog('棕色', '泰迪', 1);
26 console.log(dog1.getInstanceNumber()); //log: 2;
27 var dog3 = new Dog('黑色', '土狗', 3);
28 console.log(dog1.getInstanceNumber()); //log: 3;
29 dog1.shout(); //log: '汪!汪!汪!我是一只2岁的白色贵宾'
30 dog2.shout(); //log: '汪!汪!汪!我是一只1岁的棕色泰迪'
31 dog3.shout(); //log: '汪!汪!汪!我是一只3岁的黑色土狗'

  接下来是ES6的类的创建方法,这段代码可以直接在Chrome浏览器运行,新手可不用管这部分,包括再下面的TypeScript代码。

  

 1 class Dog {
 2     constructor(hairColor, breed, age) { //代表这个类的构造函数
 3         this.hairColor = hairColor; //string
 4         this.breed = breed; //string
 5         this.age = age; //number
 6         this.runSpeed = null; //string
 7         Dog.instanceNumber++;
 8     }
 9     shout() {
10         console.log('汪!汪!汪!我是一只' + this.age + '岁的' + this.hairColor + this.breed);
11     }
12     run() {
13         this.runSpeed = '10m/s';
14         console.log('吃我灰吧,哈哈!本狗的速度可是有' + this.runSpeed);
15     }
16     gnawBone() {
17         console.log('这是本狗最幸福的时候');
18     }
19     getInstanceNumber() {
20         return Dog.instanceNumber;
21     }
22 }//ES6类的创建就比较舒服了,class把整个类用{}包裹在一起,写法也比较方便。
23 Dog.instanceNumber = 0;//遗憾的是ES6里也没有规范静态属性,还是跟ES5一样的用法,据说ES7已有一个静态属性的提案
24 let dog1 = new Dog('白色', '贵宾', 2);
25 let dog2 = new Dog('棕色', '泰迪', 1);
26 let dog3 = new Dog('黑色', '土狗', 3);
27 dog1.shout(); //log: '汪!汪!汪!我是一只2岁的白色贵宾'
28 dog2.shout(); //log: '汪!汪!汪!我是一只1岁的棕色泰迪'
29 dog3.shout(); //log: '汪!汪!汪!我是一只3岁的黑色土狗'
30 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的一个属性;
}

 

 

  当然,你成了老司机后可以一开始就把一个对象再抽象出许多成员对象,随你喜欢。

后话

  如果你喜欢作者的文章,记得收藏,你的点赞是对作者最大的鼓励;

  作者会尽量每周更新一章,下一章是讲封装;

  大家有什么疑问可以留言或私信作者,作者尽量第一时间回复大家;

  如果老司机们觉得那里可以有不恰当的,或可以表达的更好的,欢迎指出来,作者会尽快修正、完善。

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 项目中使用TypeScript的TodoList实例详解
    项目中使用TypeScript的TodoList实例详解
    目录为什么用todolisttodolist的ts化数据到视图实现handleTodoItemreadonly分类交叉类型新增功能联合类型可选属性数据转视图总结为什么用todolist现代的框架教程目前再也不是写个hello world那么简单了,而是需要有一定基础能力能够做到数据绑定、遍历、条件
    03-16
  • React之 hook / class 结合typescript笔记
    React之 hook / class 结合typescript笔记
    使用 create-react-app 开启 TypeScriptCreate React App 是一个官方支持的创建 React 单页应用程序的CLI,它提供了一个零配置的现代构建设置。当你使用 Create React App 来创建一个新的 TypeScript React 工程时,你可以运行 npx create-react-app my-app
    03-08
  • Angular基础(三) TypeScript
    Angular基础(三) TypeScript
       一、模仿Reddita) 运行ng new –ng4angular-reddit创建应用,从随书代码中复制样式文件,新建组件app-root,代码为:界面可以看到了:b) 对于界面输入的数据,获取的方式有点特别,使用了#newlink这样的语法,newlink是一个对象,现在代表就是所在的inp
    03-08
  • electron教程(番外篇二): 使用TypeScript版本的
    electron教程(一): electron的安装和项目的创建electron教程(番外篇一): 开发环境及插件, VSCode调试, ESLint + Google JavaScript Style Guide代码规范electron教程(番外篇二): 使用TypeScript版本的electron, VSCode调试TypeScript, TS版本的ESLintelectron
    03-08
  • 使用 ESModule 和 TypeScript 构建 Node.js 环境
    使用 ESModule 和 TypeScript 构建 Node.js 环
    介绍由于我经常使用 React,所以我在前端接触过 Node.js,但我从未接触过后端。正常搭建环境的时候,不能使用import语句,变成了require语句,很不方便。我认为有各种各样的错误,所以如果你能指出它们,我将不胜感激。执行环境macOS 蒙特雷 ver12.5.1MacBook
    03-08
  • [个人发展] 我做了一个可以永远谈论任何事情的女士对话AI(TypeScript,Python)
    [个人发展] 我做了一个可以永远谈论任何事情的
    在个人发展中对话式人工智能服务 Eveki我做了虚构角色1这是一项以人工智能为特色的服务,可以再现并享受自然对话。这一次,作为第一个艾小姐发表了。请先尝试实物。服务概览与人工智能对话基本上只需输入您的信息是。对话是用女士的语言进行的,就像人类一样
    03-08
  • 使用 Node.js (TypeScript) 和 Azure Functions 创建无服务器 REST API,并获得 CosmosDB 更改源作为奖励。
    使用 Node.js (TypeScript) 和 Azure Functions
    介绍在本文中,我们将使用 azure 函数和 ComsmosDB 创建一个无服务器 REST API 应用程序。使用的语言是 Node.js/TypeScript。此外,由于我们使用 CosmosDB 作为数据库,因此我们将使用 Azure 函数触发器接收 Change Feed 事件作为奖励。创建资源创建资源组az
    03-08
  • 安装 TypeScript 并编译成JS
    安装 TypeScript 并编译成JS
    官网: https://github.com/microsoft/TypeScriptTypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码。TypeScript是一种应用级JavaScript语言。TypeScript为JavaScript添加了可选类型,支持针对任何浏
    03-08
  • 使用TypeScript,AngularJs和Web API构建基本的C
    原文地址:using typescript with angularjs and web api 版权归其作者所有.在这篇文章中我将向大家展示如何使用TypeScript,Angular Js 和Asp.net Web API 来构建一个基本的实现CRUD功能的Web应用程序. Typescript提供了一系列的功能来方便程序员构造和组织更
    02-10
  • Typescript 中类的继承
    Typescript中类的定义与继承与后端开发语言java/C#等非常像,实现起来非常方便,而且代码便于阅读。用Typescript写较大项目时是非常有优势的。/** * BaseClass */class BaseClass {constructor(name:string,age:number) {this.name=name;this.age=age;}name:s
    02-09
点击排行