ES6-18:class类及其继承

JavaScript作为一个动态语言,很大程度上的诟病就是缺少了面向对象的这个概念,ES5传统的方法是通过构造函数来实现类的特性;ES6引入了类这一概念,将Class这个概念作为对象的模板,通过关键字class可以定义类;本质上ES6中引入的类是一个语法糖,其大部分功能ES5均可实现;

JavaScript语言可以实现继承的特征,但ES5与ES6在实现的机制上确迥然不同:

  • ES5继承的实质:先创造子类的实例对象this,然后将父类的方法添加到this上面,及Parent.apply(this);
  • ES6继承的实质:先创造父类的实例对象this,然后再用子类的构造函数修改 this,因此ES6子类继承必须先调用super方法;

1.类与对象的区别

1. 先来看一下对象和类的定义
②对象,是一个具体的个体,拥有对象名、属性、方法三个特征;每个对象拥有自己独立的属性,依靠属性来区分不同的对象,方法是对象的动态属性,也成为方法/服务;每个方法用来确定对象的一种行为或功能;   
①类,是抽象的概念集合,拥有类标识、属性、方法三个特征,是一类具有相同特性的个体的抽象和归纳;类是抽象出能反映与当前目标有关的本质特征,忽略那些与当前目标无关的非本质特征,从而找出事物的共性,把具有共同性质的事物归结为一类,进而抽象出的概念;

类的变量:一个类所包含的变量根据其可访问性的差别分为:①局部变量:定义在方法、构造方法、语句块中的变量,方法结束后变量就自动销毁;②成员变量:定义在类中,方法体之外的变量,可被类中的方法、构造方法、语句块访问;③成员变量:定义在类中,方法体之外,且用static修饰的变量;

类的修饰符:类的变量修饰符有4种:publicprivateprotectedfriendly;类的方法有7种修饰符:publicprivateprotectedstaticabstractfinalsynchronized;其区别如下:

  • public:在类中任意地方可见、对子类可见、对继承对象可见;
  • private:在类中任意地方可见、在类外不可见;
  • protected:在类中任意地方可见、在类外不可见,不可被外部修改

类和对象都是面向对象程序设计的基本组成单元,但两者又有所不同,简单来说:
两者之间的主要区别如下:

  • 类是对象的模板,对象是类的实例;
  • 类不能直接使用,只有通过对象才可使用,而对象可以直接使用;
  • 类需要在对象之前创建,对象可以继承类;
  • 类和对象都具有一系列属性(静态属性)、方法(动态属性/服务/操作);

2. ES6 类的特性

  • 类的数据类型就是函数,类本身指向构造函数;
  • 类具有构造方法constructor(),类内部this指向实例对象;
  • 类的所有方法都定义在类的prototype属性上,类方法的调用其调用实质上就是调用原型上的方法;
  • 类内部定义的所有方法都是不可枚举的;而ES5原型上的所有方法都是可以枚举的;
  • 类的属性名可以采用表达式;
  • 类和模块内部默认使用严格模式;
  • 类的方法之间不需要逗号分隔,加了会报错;
  • 类必须用new来调用,否则会报错;
  • 类的实例化对象必须使用new,否则会报错;
  • 类中变量的定义不存在变量提升,这一点是为了保证子类继承必须在父类之后定义
// 案例1:类的创建
class Person{};      // 类声名方式
class Cat=class cat{};// 表达式方式

// 案例2
class Person1{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    sayHi(){
        console.log('My name is'+this.name+'; and I'm '+this.age);
    }
}
Person1===Person1.prototype.constructor;//true
// 以上写法和下面写法本质上一样
class Person2{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
};
Person2.prototype.sayHi=function(){
    console.log('My name is'+this.name+'; and I'm '+this.age);
}
// 或
class Person2{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
};
Person2.prototype={
    sayHi(){
        console.log('My name is'+this.name+'; and I'm '+this.age);
    }
}

3. ES6类的私有属性、私有方法

ES6并没有提供类的私有属性、私有方法特性,所以私有属性、私有方法都需要通过其他方法模拟实现;

  • 私有属性实现:私有属性提案属性前加#
class Piont{
    #x
    cnstructor(x=0){
        #x=x*2;
    }
}
  • 私有方法实现:利用Symbol+表达式方法名;
const foo=Symbol('foo');
export default class Cat{
    bar(){console.log('这是一个公有方法')}
    [foo](){console.log('这是一个私有方法)}
}

4. ES6类中静态属性、静态方法

类是实例的原型,所有类中的方法和属性都会被实例继承,而静态属性、静态方法不会被实例继承,可以被子类继承,并且通过直接调用;类中的静态属性、静态方法在类中都采用static关键字;此外静态属性和静态方法还可以在类外部定义

// 示例1 关键字stativc定义静态属性、静态方法
class Foo{
    name=1;
    static age=2;
    sayMethod(){console.log('这是一个公有方法')}
    static say(){console.log('这是一个私有方法')}  
}
let foo=new Foo();
class Bar extends Foo{};


consle.log(foo.name);//1
consle.log(foo.age);// Type Error foo.age is undefined
Foo.say(); // 这是一个私有方法
bar.say();  // 这是一个私有方法
foo.sayMethod(); // 这是一个公有方法
foo.say();   // TyoeError: foo.say is not a function

5. Class.name 、new.target属性

  • name属性:返回一个类的标识;
  • target属性:返回new命令所用的构造函数,而子类继承父类,是new.target返回子类;该属性可用于确定构造函数是如何调用的;
// name属性
class Foo{};
console.og(foo.name);//Foo
// target属性
class Person{
    constructor(age,name){
        this.age=age;
        this.width=name;
        console.log(new.target===Person);
    }
}
var obj=new Person(13,'John');// true
var obj0=Person.call(obj,(24,'Lilly'));//false
class Person1 extends Person{
    constructor(age,name){
        super(age,name);
    }
}
let obj1=new Person1(23,'Jim');// false

6. ES6类的继承

参考:

posted @ 2018-01-21 13:52  hbzyin  阅读(1037)  评论(0编辑  收藏  举报