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种:
public
、private
、protected
、friendly
;类的方法有7种修饰符:public
、private
、protected
、static
、abstract
、final
、synchronized
;其区别如下:
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类的继承
参考: