在上一篇文章里我介绍了一下面向对象编程的概念,在最后终于喜出望外看到了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
关键字,如下图:
下面我要详细的对比一下ES5
与ES6
的面向对象有什么区别,以及用这种方式写出来的对象与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"] 所有方法都是可枚举的
从上面的代码得出以下的结论
类的本质还是构造函数,其实class就是个语法糖,它的内部还是个构造函数
class声明的对象与ES5声明的对象实质上一样
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), //内置对象身上的方法都是不可枚举的);
从上面的代码得出以下的结论
自定义对象就是我们声明的一个类似于内置对象的对象
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(); //报错,它是私有方法