再和“面向对象”谈恋爱 - class(四)

阮小二
• 阅读 1516

上一篇文章里我介绍了一下面向对象编程的概念,在最后终于喜出望外看到了ES6提供了类的概念了。那这个类如何去用,是这篇文章的主题。ES6给我们提供了一个class关键字。这个关键字跟以前的var let const很像,它们都是用做声明的,而class就是用来声明一个类的。

语法

class name [extends]{   //extends是用来继承的,可选参数
    //class body
};

注意

  • class不能重复声明(与let、const一样)
  • 类的本质还是一个构造函数
class Div{  //类
    constructor(x,y){   //构造函数
        this.x=x;    //共享属性,放在constructor里
        this.y=y;
    }//注意这里是没有逗号的
    move(){    //共享方法,这里相当于在Div.prototye上添加方法
        console.log('动起来');
    }
}
console.dir(Div);   //在控制台里看一下与ES5的面向对象程序有什么不同

ES5里面的面向对象,所谓的“类”与构造函数其实是一个东西,也就是双重角色。而到了ES6里面真正的类与构造函数现在是分离的,通过上面的代码可以看出来,这种写法正是面向对象的正统写法。同时,我们在控制台里看到这个对象与ES5的对象区别仅在于显示的名字上多了一个class关键字,如下图:
再和“面向对象”谈恋爱 - class(四)

下面我要详细的对比一下ES5ES6的面向对象有什么区别,以及用这种方式写出来的对象与ECMAScript的内置对象有什么区别,这样做的目的能让你清晰的明白面向对象编程究竟是一种什么样的形式。

1、与ES5对比

const [div1,div2]=[new Div(10,20),new Div(15,20)];    //这两个对象是为了对比他们身上的原型
div1.z=30;    //给实例添加一个私有属性

console.log(
    typeof Div,    //function 构造函数(虽说是类,但实质还是构造函数)
    Div.prototype.constructor===Div,    //true 类本质还是构造函数(披着羊皮的狼)
    
    //Object.getPrototypeOf方法是用来取对象身上的原型,用它代替__proto__
    Object.getPrototypeOf(div1)===Div.prototype,    //true 实例的原型就是构造函数的原型
    Object.getPrototypeOf(div1)===Object.getPrototypeOf(div2),  //true 两个实例的原型都一样,指向构造函数的原型对象
    
    div1 instanceof Div,        //true div是它的实例
    div1.constructor===Div,        //true 实例的构造函数就是类
    
    /*
     * 方法说明
     *  Object.getOwnPropertyNames()这个方法是用来获取对象身上的所有属性名
     *  hasOwnProperty()用来判断某个属性是对象自身的(true),还是继承自原型对象的(false)
     *  Object.keys()返回对象所有可枚举(遍历)的属性名
     */
    Object.getOwnPropertyNames(div1),//["x", "y", "z"] 实例自己的属性
    div1.hasOwnProperty('x'),        //true 实例的属性
    div1.hasOwnProperty('move'),    //false 这个方法是继承而来的
    Object.keys(Div.prototype)        //[] 对象身上的方法都是不可枚举的
);

//ES5定义的对象,身上的方法是可以枚举的
function Car(){}
Car.prototype.drive=function(){
    console.log('窜的老快了');
}
console.log(Object.keys(Car.prototype));  //["drive"] 所有方法都是可枚举的

从上面的代码得出以下的结论

  1. 类的本质还是构造函数,其实class就是个语法糖,它的内部还是个构造函数
  2. class声明的对象与ES5声明的对象实质上一样
  3. class声明的对象,它身上的方法都不能被枚举

2、与内置对象对比

const [d1,d2]=[new Date(),new Date()];  //声明两个内置对象实例
d1.x=10,d1.y=20,d1.z=30;    //给实例添加三个私有属性

console.log(
    typeof Date,    //function
    Date.prototype.constructor===Date,    //true
    Object.getPrototypeOf(d1)===Date.prototype, //true
    Object.getPrototypeOf(d1)===Object.getPrototypeOf(d1),  //true
    d1 instanceof Date, //true
    d1.constructor===Date,  //true
    Object.getOwnPropertyNames(d1), //["x", "y", "z"]
    d1.hasOwnProperty('x'),  //true
    d1.hasOwnProperty('getDate'),   //false 这个方法是继承于Date对象的
    Object.keys(Date.prototype),    //内置对象身上的方法都是不可枚举的
);

从上面的代码得出以下的结论

  1. 自定义对象就是我们声明的一个类似于内置对象的对象
  2. JavaScript的面向对象编程,实质是把某个功能写成一个对象,并且这个对象是在模仿内置对象

添加属性与方法

class声明的对象同样允许小伙伴们任性的添加属性与方法,包括共享与私有的。

  • 共享属性放在constructor里,共享方法放在大括号内
  • 私有属性放在类身上,私有方法放在大括号内同时前面要加static关键字
  • 私有方法里this指向类本身,其它方法里的this指向实例对象
class Bear{
    constructor(){
        this.name='熊大';   //共享属性(放在constructor里)
    }
    sleep(){    //共享方法(直接放在大括号里)
        this.name='熊二';    //this指向实例,所以在这里给this添加属性还是实例的属性
        console.log(`${this.name}爱睡觉`);
    }
    static gohome(){    //私有方法
        //类会默认添加一个name属性,值为class后面的那个单词
        console.log(`${this.name}的家在森林`);  //这里的this并不会指向实例,而是指向类
    }
}

//共享属性与方法
const b1=new Bear();
console.log(b1.name);    //熊大    
b1.sleep();    //熊大爱睡觉
console.log(b1.name);    //熊二  sleep里重新定义了name属性,所以在这就被改了

//私有属性与方法
Bear.age=5;        //在外面添加私有属性
console.log(b1.age);    //undefined 实例不具备
Bear.gohome();            //Bear的家在森林
//b1.goHome();            //报错,它是私有方法

下篇文章会详细介绍class里的继承。

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Easter79 Easter79
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这