下面的对ES6中class关键字的整理,希望可以帮助到有需要的小伙伴~
传统面向对象是基于类的面向对象,类的继承实际上是构造函数的继承
JSON是基于原型的面向对象
es6 给了JSON类的语法规则,但是底层没有提供类,底层是构造函数。类的继承实际上是构造函数的继承。
// 这个原型指向对象
Hero.prototype = {
age : 18,
myJob : function () {
console.log("eat");
}
}
var hero = new Hero();
// ES6创建类
class Hero {
// 构造器
constructor() {
this.name = "张无忌";
this.sayMe = function () {
console.log("this is 张无忌");
}
}
}
类的声明
声明类具有以下两种方式:
-
类的声明方式
class name [extends]{ // class body }
-
name: 表示当前声明的类名。
-
extends:继承
但是不同于类表达式,类声明不允许再次声明已经存在的类,否则将会抛出一个类型错误。
-
-
类的表达式方式
const MyClass = class [className][extends]{ // class body ); // 或者 let MyClass = class [className][extends]{ // class body ); // 或者 var MyClass = class [className][extends]{ // class body );
和函数表达式相同的一点是,类表达式可以是命名也可以是匿名的。如果是命名类表达式,这个名字只能在类体内部才能访问到。
实例:
/*
1. 类的声明方式
class className {
内部结构
}
* class关键字 - 用于创建类
* className - 创建的类名
* 使用类的声明方式时–不允许重复声明的
*/
class Hero {}
/*
2.类的表达式方式
const/let/var className = class [className]{
内部结构
}
* class关键字 – 用于创建类
* myclass/className - 表示创建的类名
* myClass -类名,用于后面的代码逻辑进行调用
* className -类名,用于当前类的内部使用的
*/
const myHero = class Hero {}
// 使用var关键字可以重复声明一个类,其余声明类的方式都不允许重复声明
var myHero2 = class Hero2 {}
var myHero2 = class Hero2 {}
构造函数
构造函数(Constructor )是用于创建和初始化类中创建的一个对象的一种特殊方法。
constructor([arguments]) { ...}
- 在一个类中只能有一个名为“constructor”的特殊方法。一个类中出现多次构造函数(Constructor)方法将会抛出一个SyntaxError错误。
- 在一个构造方法中可以使用super关键字来调用一个父类的构造方法。
- 如果没有显式指定构造方法,则会添加默认的constructor方法。
- 如果不指定一个构造函数( constructor )方法,则使用一个默认的构造函数( constructor ) 。
/*
创建类 - 结构
* 外层的类的语法结构
* 内层的构造器的语法结构
*/
class Hero {
// 构造器
constructor() {
this.name = "Jenny";
this.sayMe = () => {
console.log("this is Jenny");
}
}
}
let hero = new Hero();
console.log(hero); // Hero { name: 'Jenny', sayMe: [Function] }
hero.sayMe(); // this is Jenny
getter与setter
与ECMAScript 5一样,在“类”的内部可以使用get和 set 关键字(不可以自己定义),对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
在ES5中,et 和 set 是函数名,可以自己定义
/*// ES5 - get 和 set 是函数名,可以自己定义
function fn() {
var v = 100; // 局部变量
return {
get : function () {
return v;
},
set : function (value) {
v = value;
}
}
}
var obj = fn();
console.log(obj.get()); // 100
obj.set(99);
console.log(obj.get()); // 99*/
/*function fn() {
var v = 100;
this.get = function () {
return v;
}
this.set = function (value) {
v = value;
}
}
var obj = new fn();
obj.set(999);
console.log(obj.get()); // 999*/
// ES6
// 创建对象的属性 可以 设置和获取
/*class Hero {
constructor() {
this.v = 100;
}
}
var hero = new Hero();
console.log(hero.v); // 100*/
// get 和 set [关键字]
class Hero {
constructor() {
this.v = 100;
}
get getV() {
return this.v;
}
set setV(value) {
this.v = value;
}
}
var hero = new Hero();
console.log(hero); // Hero { v: 100 } 没有get和set方法
hero.getV(); // TypeError: hero.getV is not a function
console.log(hero.v);
console.log();
// 可以设置一个属性 没有自带的 get和set Object.defineProperty
不允许提前声明
声明类时,是不存在声明提前的现象的。如下示例代码所示:
new Foo():// ReferenceError: Foo is not defined
class Foo {}
上述代码示例中,Foo类调用在前,声明在后。由于ECMAScript6不允许类的声明提前,结果为报错。
这种规定的原因与继承有关,必须保证子类在父类之后定义。
不允许重复声明
声明类时,是不存在重复声明的。如果一个类被重复声明的话,则引起解析错误。
如下示例代码所示:
class Foo {};
class Foo {}; // SyntaxError; ldentifier 'Foo' has already been declared
若之前使用类表达式定义了一个类,则再次声明这个类同样会引起解析错误。
let Foo = class {};
class Foo {}}; // SvntaxError; ldentifier 'Foo' has already been declared
静态方法
静态方法的语法
static关键字为一个类定义了一个静态方法。静态方法不会在类的实例(通过类生成的对象)上被调用,相反被类本身调用。
static methodName() {...}
methodName:表示指定类中的静态方法名称。
注意:
静态方法直接在类上进行调用,不能在类的实例上调用。
ES6 实例:
/*
在类的声明中
* 构造器和普通方法中的this -> 指代创建后的对象
* 静态方法中的this -> 指代当前的类
*/
class Hero {
constructor() {
this.name = "lucy";
this.sayMe = ()=>{
console.log("this is " + this.name); // this指向的是当前对象
// 在构造器中调用静态方法,
// 1.类名直接调用 即 类名.静态方法()
Hero.sayYou(); // this is sayYou
// 2. this.constructor.静态方法名()
this.constructor.sayYou(); // this is sayYou
}
}
// 对象的方法有2种 - 可枚举 / 不可枚举
// 在构造器外面定义方法 - 不可枚举(存在但不能直接打印)
toString () {
console.log("name toString" + this.name);
// this指向的是当前对象
// return "name toString " + this.name
}
static sayYou() {
console.log("this is sayYou"); // this指向的是当前类
}
static sayHe() {
// 在当前静态方法中,调用另一个静态方法
this.sayYou();
}
}
let hero = new Hero();
hero.sayMe(); // this is lucy
console.log(hero.toString()); // undefined toString()方法中没有return语句,是打印不出结果的
// console.log(hero.toString()); // name toString lucy
// 调用sayYou()静态方法
Hero.sayYou(); // this is sayYou
// 调用sayHe()静态方法
Hero.sayHe(); // this is sayYou
类的继承
实现类的继承
类的继承在底层中实际上是 原型的继承
语法:
class ChildClass extends ParentClass {...}
- extends:使用class创建类的时候,用extends指出该类的父类
注意:
-
必须在子类的构造器中写入
super()
,该super()
指向父类的构造器,子类才能获取到父类构造器中的属性和方法 -
继承的.prototype必须是一个Object或者null.
class Parent {
constructor() {
this.name = 'parent';
this.sayMe = function() {
console.log('this is sayme')
}
}
sayYou() {
console.log("这是父类的一个普通方法"); // 这是父类的一个普通方法 undefined
}
static staticMethod() {
console.log("这是父类的静态方法");
}
}
// 声明Child类时,指定Child类作为Parent类的子类
class Child extends Parent {
constructor() {
super(); // super -> 指向当前子类的父类的构造器,否则获取不到父类构造器中的属性和方法
this.age = 18;
}
}
let child = new Child(); //
console.log(child); // Child { name: 'parent', sayMe: [Function], age: 18 }
console.log(child.sayYou()); //这是父类的一个普通方法
console.log(Parent.staticMethod()); // 这是父类的静态方法 undefined
继承于内置对象
写一个类继承于内置对象,基于内置对象扩充自己需要的方法,不会改变内置对象原型的内容。
之前使用原型方法的时候,把自己定义的方法加在了内置方法的原型上,改变了内置方法的原型,是不友好的
实例:
/*// myDate类继承于内置对象Date
class myDate extends Date{
constructor() {
super();
}
getFormattedDate(){
}
}
let date = new Date();
console.log(date.getFullYear()); // 2020 只能单独返回年、月、日*/
// 继承于Date内置对象
// myDate类继承于内置对象Date
class myDate extends Date{
constructor() {
super();
}
// 自己定义方法 返回 年-月-日
getFormattedDate(){
var months = ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"];
// 日 - 月 - 年
return this.getDate() + "-" + months[this.getMonth()] + "-" + this.getFullYear();
}
}
/*
let date = new Date();
console.log(date.getFullYear()); // 2020 只能单独返回年、月、日*/
let date = new myDate();
console.log(date.getFormattedDate()); // 25-12月-2020
// 2.继承于数组
let arr = [1,2,3,4,5,4,3,2,1];
class MyArray extends Array {
constructor() {
super();
}
// Set数据结构中的值是唯一的,可以利用Set给数组中的值去重
quchong(array) {
return new Set(array);
}
}
var array = new MyArray();
console.log(array.quchong(arr)); // Set { 1, 2, 3, 4, 5 }
Super关键字
super关键字可以当作函数使用、当作对象使用。这两种情况是不同的。
-
super关键字当作函数调用 - 代表父类的构造函数
ES6要求子类的构造函数必须执行一次super函数
注意:
super虽然代表了父类A的构造函数,但是返回的是子类B的实例
即 super内部的 this指的是B,因此 super()在这里相当于A.prototype.constructor.call(this)。
-
super关键字作为对象
- 在普通方法中,指向父类的原型对象
- 在静态方法中,指向父类
注意:
由于super指向父类的原型对象,super()不能调用定义是父类实例上的方法和属性。
类的实例
注意:父类中方法的返回值 必须用 return , 否则会返回undefined
// 定义一个类
class Parent {
// 当前的构造器(如果省略,JS会自动生成一个构造器)- 创建对象的初始化方法
constructor(name) {
this.name = name;
}
// 当前类的(实例对象的)方法,不是当前类的原型方法
toString() {
console.log("this is toString method");
}
// 静态方法 - 由当前类直接调用的方法
static staticMethod() {
return "this is static method";
}
}
// super作为对象,在普通方法中指向父类的原型对象,所以父类中的toString()方法必须是原型中的方法
// 在类的原型中添加方法
Parent.prototype.sayMe = function () {
return "this is parent method."
}
// 类也同样具有原型(类似于ES5中的构造函数)
// 对象中有一个隐式原型 - 指向类的原型
/*let parent = new Parent();
parent.toString(); // this is parent method.*/
// 定义一个类作为另一个类的子类
class Child extends Parent {
// 因为父类的构造函数中有一个name形参,所以子类的构造函数中也要有和父类一样是形参,否则子类就不能继承父类了
// 别忘了 super()里面也要写上父类中构造函数的形参
constructor(name,age) {
super(name); // super指向父类的构造器
this.age = age;
// 以下用法:super -> 指向父类的实例对象(具有隐式原型)
// 原型对象不能调用实例对象,实例对象能调用原型对象
super.sayMe(); // super指向父类的原型对象
// super.staticMethod(); // 报错 TypeError: (intermediate value).sayMe is not a function
super.toString(); // super指向父类实例化的对象 this is tostring method .
// super的不同用法导致super的含义不同
}
sayMe() {
// super 指向父类的原型对象
console.log("this is child method. " + super.sayMe())
}
static staticMethod() {
// super - 指向父类
console.log("this is child static method. " + super.staticMethod())
}
}
// 因为子类的构造函数中有形参name 和 age , 所以实例化子类的时候也要给形参传值
let child = new Child("lucy",18);
// console.log(child); // Child { name: 'lucy', age: 18 }
// 父类和子类中有相同函数名toString(),当子类对象调用该方法的时候,子类和父类的相同方法会被同时调用
child.sayMe();
/*
this is parent method.
this is child method. undefined
如果 super.staticMethod() 的返回值是 undefined
原因:super作为对象,在普通方法中指向父类的原型对象,而父类中的toString()方法不是原型中的方法
把父类中的toString()方法改为原型中的方法后:
返回结果是:
this is child method. this is parent method.
*/
// Child.staticMethod();
/*
this is static method
this is child static method. undefined
*/
end~