1.Class类的介绍

在ES6中新增了Class类的概念,让语法看起来更像是面向对象编程,其实这可以说是一个语法糖,ES5可以做到Class绝大部分功能,但也有一些不同。在ES6以前,可以通过构造函数来模拟类的概念,如下所示

function Student(name,age){
this.name = name;
this.age = age;
}
Student.prototype = {
constructor:Student,
show:function(){
console.log(this.name,this.age);
}
};
var xiaoming = new Student("xiaoming",20);
xiaoming.show();
xiaoming 20

在引入了Class关键字后,可以这样做,如下所示

class Person{
constructor(name,age){ //构造函数,默认返回this对象,如果强制返回其他对象也是被允许的
this.name = name;
this.age = age;
}
show(){
console.log(this.name,this.age);
}
}
var s = new Person('test',30);
s.show();
test 30

如上所示,便是ES6中类的定义,上面的constructor函数是类的构造函数,如果不写,则会自动创建一个constructor空构造函数,并且方法之间不允许有逗号,否则会报错,如下所示

class Person{
show(){
alert("show");
},
hide(){
alert("hide");
}
}
var s = new Person();
s.show();
SyntaxError: invalid property id

其实类的数据类型就是函数,类本身就指向构造函数,如下所示

class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
show(){
console.log(this.name,this.age);
}
}
typeof Person
"function"
Person.prototype.constructor===Person
true
var p = new Person('test',20);
undefined
p.constructor
function Person()
p.constructor == Person
true

prototype属性在类上依旧存在,且类的方法都定义在类的prototype上面,如下所示

var person = new Person('person',100);
person.constructor === Person.prototype.constructor
true

因此可以在类的prototype上面定义的新方法为类扩展方法,如下所示

Object.assign(Person.prototype,{show(){console.log(this.name);}});
person.show();
var a = new Person('nihao',20);
a.show(); person
nihao

但是类内部定义的方法是不可枚举的,这和ES5的构造函数还是有很大的区别,如下所示

Object.getOwnPropertyNames(Person.prototype)
Array [ "constructor", "show" ]
Object.keys(Person.prototype)
Array [ ]

类的属性名可以使用表达式来定义,如下所示

var show = 'show';
class Test{
constructor(){
console.log("class test constructing...");
}
[show](){
console.log('show');
}
}
var test = new Test();
test[show]();
class test constructing...
show

在生成类的实例对象时,必须使用new关键字,如果直接像调用函数那样调用类,则会报错,如下所示

var t1 = Test();
TypeError: class constructors must be invoked with |new|

类的所有实例共享一个原型,实例对象可以通过__proto__属性来访问原型,因此可以通过该属性为原型添加方法,如下所示

test.__proto__.say = () => "hello prototype!";
test.say();
new Test().say();
class test constructing...
"hello prototype!"
test.say()

类Class也可以像Function一样,采用表达式形式来定义,如下所示

var Aclass = class Bclass{
constructor(){
console.log(Bclass.name);//只有在类的内部才能访问到Bclass
}
show(){
console.log('Aclass...');
}
};
var a = new Aclass();
a.show();
Bclass
Aclass...

因此我们可以写出类似立执行函数的立执行类,如下所示

var iifeInstance = new class{
constructor(text){
this.text = text;
}
show(){
console.log(this.text);
}
}('iife testing...');
iifeInstance.show();
iife testing...

类的定义不存在变量声明提升,这和ES5函数不同,如下图所示

var a = new Dclass();
class Dclass{ }
ReferenceError: can't access lexical declaration `Dclass' before initialization

2.Class类的继承

Class类的继承通过关键字extends来实现,和ES5通过修改原型链实现继承不同,如下所示

class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
print(){
console.log(this.name,this.age);
}
}
class Student extends Person{
constructor(name,age,sno){
super(name,age); //调用父类的构造函数,必须存在且需放在子类使用this对象之前,否则将报错
this.sno = sno;
}
print(){
super.print();
console.log(this.sno);
}
}
var s = new Student('xiaoming',20,"21014130217");
s.print();
xiaoming 20
21014130217

值得注意的是在定义子类构造函数时,一定要调用父类的构造函数且必须在子类使用this对象之前,因为子类不存在this对象,需要使用super得到父类的this对象,然后对其进行改写加工。如果缺省构造函数,则会自动创建一个默认的构造函数并调用父类的构造函数

子类的原型prototype是父类的实例,有点像原型链继承,子类__proto__指向父类,这和函数的默认继承不同。如下所示

Student.prototype instanceof Person
true
Student.prototype.__proto__ === Person.prototype
true
s.__proto__ === Student.prototype
true
Student.__proto__ === Person
true

可以使用Object.getPrototypeOf获取子类的父类,如下所示

Object.getPrototypeOf(Student) === Person
true

3.原生构造函数的继承

在ES5中不能继承原生的构造函数,例如Array,Date,Object,Function等等,但是在ES6中可以实现对原生构造函数的继承,如下所示

class MyArray extends Array{
constructor(){
super();
this.sign = "myArray";
}
}
var myArr = new MyArray();
console.log(myArr);
myArr.push(1,2,3);
console.log(myArr);
Array [ ]
Array [ 1, 2, 3 ]
console.log(myArr.sign);
"myArray"

但是在继承Object时,有一点差异就是调用super给Object构造函数传参时会被忽略,这是ES6在实现时检测到不是以new Object形式调用构造函数,则忽略参数,如下所示

class MyObj extends Object{
constructor(arg){
super(arg);
this.sign = "MyObj";
}
}
var myObj = new MyObj({x:1});
console.log(myObj.x);
undefined

3.类的getter和setter函数,与ES5中的一样,都是对类属性存取行为的拦截,如下所示

class Xclass{
constructor(){
console.log('Xclass initializing...');
}
set x(val){
console.log(val);
}
get x(){
return 2;
}
} var xIns = new Xclass();
xIns.x = 4;
console.log(xIns.x);
Xclass initializing...
4
2

4.类的静态方法与静态属性

静态方法与属性不能被实例对象调用,静态方法可以在类内部定义,但静态属性则不能,静态方法可以被子类继承,如下所示

class StaticTest{
static test(){
console.log('static...');
}
}
class SubStatic extends StaticTest{
show(){
console.log('substatic show...');
}
}
StaticTest.test();
SubStatic.test();
new SubStatic().show();
new StaticTest().test();
static... 2次
substatic show...
TypeError: (intermediate value).test is not a function

静态属性的定义则是直接使用ClassName.prop形式来定义,如下所示

class StaticTest{
static test(){
console.log('static...');
}
}
StaticTest.xxx = "hello class static variable";
StaticTest.xxx;
"hello class static variable"

5.new.target

在ES6中为new命令添加了一个target属性,该属性在构造函数中返回new命令作用于的那个函数,如果不是以new命令调用构造函数则返回undefined,如下所示

class Target{
constructor(){
console.log(Object.is(new.target,Target));
}
}
var target = new Target();
true

有了这个属性,我们可以强制构造函数必须以new命令实例化,如下所示

function Animal(name){
if(!new.target) throw new Error('必须使用new实例化Animal');
this.name = name;
}
var duck1 = new Animal('duck1');
console.log(duck1.name);
var duck2 = Animal('duck2');
duck1
Error: 必须使用new实例化Animal

也可以用来模仿抽象类,不能被实例化,只能被继承使用

class Car{
constructor(brand){
if(new.target === Car) throw new Error('Car类不能被实例化');
this.brand = brand;
}
}
class Baoma extends Car{
constructor(brand){
super(brand);
}
showBrand(){
console.log(this.brand);
}
}
var baoma = new Baoma('baoma');
baoma.showBrand();
baoma
var car = new Car('car');
Error: Car类不能被实例化

在实例化子类时,父类的new.target指向的是子类。

  

 

ES6 - Note4:Class类的更多相关文章

  1. Nodejs与ES6系列4:ES6中的类

    ES6中的类 4.1.class基本语法 在之前的javascript语法中是不存在class这样的概念,如果要通过构造函数生成一个新对象代码 function Shape(width,height) ...

  2. ES6中的类

    前面的话 大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,这种状态一直延续到了ES5.由于类似的库层出不穷,最终还是在ECMAScri ...

  3. 深入理解ES6之——JS类的相关知识

    基本的类声明 类声明以class关键字开始,其后是类的名称:剩余部分的语法看起来像对象字面量中的方法简写,并且在方法之间不需要使用逗号. class Person { //等价于prototype的构 ...

  4. ES6中的类和继承

    class的写法及继承 JavaScript 语言中,生成实例对象的传统方法是通过构造函数.下面是一个例子     function Point(x, y) {  this.x = x;  this. ...

  5. ES6中的类继承和ES5中的继承模式详解

    1.ES5中的继承模式 我们先看ES5中的继承. 既然要实现继承,首先我们得要有一个父类. Animal.prototype.eat = function(food) { console.log(th ...

  6. 160803、如何在ES6中管理类的私有数据

    如何在ES6中管理类的私有数据?本文为你介绍四种方法: 在类的构造函数作用域中处理私有数据成员 遵照命名约定(例如前置下划线)标记私有属性 将私有数据保存在WeakMap中 使用Symbol作为私有属 ...

  7. ES6里关于类的拓展(二):继承与派生类

    继承与派生类 在ES6之前,实现继承与自定义类型是一个不小的工作.严格意义上的继承需要多个步骤实现 function Rectangle(length, width) { this.length = ...

  8. ES6里关于类的拓展(一)

    大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,这种状态一直延续到了ES5.由于类似的库层出不穷,最终还是在ECMAScript 6中 ...

  9. es6入门5--class类的基本用法

    在ES6之前,准确来说JavaScript语言并无类的概念,却有模拟类的做法.相比在类似java这类传统面向对象语言中通过类来生成实例,js则通过构造函数模拟类来生成实例. 这是因为在JS设计初期,作 ...

  10. TypeScript完全解读(26课时)_7.ES6精讲 - 类Class基础

    ES6精讲 - 类Class基础 es5中创建构造函数和实例 原来在es5中的写法 定义好Point后,在原型对象上定义getPostion的方法 实例自身是没有这个方法的,我们调用的时候会去创建他的 ...

随机推荐

  1. JS中检测数据类型的几种方式及优缺点【转】

    1.typeof 用来检测数据类型的运算符 typeof value 返回值首先是一个字符串,其次里面包含了对应的数据类型,例如:"number"."string&quo ...

  2. TortoiseSVN 合并操作简明教程

    下列步骤展示了如何将分支A中的修改合并到分支B. 1.在分支B的本地副本目录中选择"合并(Merge)". 2.选择“合并一个版本范围(Merge a range of revis ...

  3. <十>JDBC_处理Blob类型数据

    /*  * 读取BLOB数据:  *  使用getBlob方法读取到Blob对象  *  调用Blob的getBinaryStream(方法得到输入流,在使用IO操作  * */ @Test publ ...

  4. 深入浅出 妙用Javascript中apply、call、bind

    apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Jav ...

  5. Allegro之无法保存(提示和用户有关或者和lock有关)

    使用中无意出现此情况 无奈重新打开文件时发现brd文件下面有个.brd.lck文件,顺手删掉,回复正常~ 此为bug解bug,具体方法下次遇到再仔细研究是为什么~ 养成隔几分钟手动保存的好习惯,防止b ...

  6. siteserver cms分页

    <stl:pageContents pageNum="10" cellpadding="2" cellspacing="2"> ...

  7. Android 圆形图片加白边加阴影

    /** * 将图片准转为圆形 * * @param bitmap * @return */ public static Bitmap getRoundedCornerBitmap(String pat ...

  8. Git 常用命令大全

    Git常用操作命令: 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git 查看远程仓库:$ git remote -v 添加 ...

  9. PHP好任性 —— 大小写敏感有两种规则,然而并没有什么特别原因

    大小写敏感 变量.常量大小写敏感 大小写不敏感 类名.方法名.函数名.魔法变量大小写不敏感 原因 有人原引了Rasmus 在一次会议上的发言大意: "I'm definitely not a ...

  10. 导向矢量(Steering Vector)

    导向矢量是阵列天线的所有阵元对具有单位能量窄带信源的响应. 由于阵列响应在不同方向上是不同的,导向矢量与信源的方向是相互关联的,这种关联的独特性依赖于阵列的几何结构.对于同一阵元阵列,导向矢量的每一个 ...