乐趣区

关于前端:详解ES6关键字Class

“ 小和山的菜鸟们 ”,为前端开发者提供技术相干资讯以及系列根底文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 (https://xhs-rookies.com/) 进行学习,及时获取最新文章。

本文通过以下几个方面来谈谈 ES6 中新增的关键字Class

  • 背景
  • 如何应用 Class
  • 横向、纵向比照
  • JavaScript 是如何实现 Class 的
  • Class 关键字的限度
  • 总结

1. 背景

1.1 Class 的来历

Class由 2015 年的 ES6 中正式提出,然而这个关键字最早于一篇 JavaScript 的草案 JavaScript 2.0 Classes (mozilla.org)中提出(1999.02),过后因为该关键字过于激进,导致 ES4 并未将 JavaScript2.0 中的 class 关键字合并进去,直到 ES6 草案的提出和通过。

1.2 ES6 退出 Class 的起因

咱们在 TC39 的 GitHub 找到了 ES6 的提案,在 Stage0 阶段对于 Class 的提案中找到了如下解释:

翻译:

ECMAScript 曾经领有了十分齐备的性能来定义各种事物的形象。构造函数、原型、实例这三个的个性足以让实现那些别的语言中类能做到的事。这个稻草人(临时了解为 性能)的目标不是扭转那些语义。相同的,为这些语义提供简洁的申明性示意,可能分明的表白出程序员的用意而不是底层的命令性机制。艰深来说,Class关键字给咱们提供了一种形式,来到那些繁的prototypecall,写出逻辑清晰的代码。

2. 如何应用 Class

2.1 创立类

应用ES6 中的 Class 来实现类

//ES6
class Employee {constructor(name, dept) {
    this.name = name
    this.dept = dept
  }
  static fun() {console.log('static')
  }
  getName() {console.log(this.name)
  }
}

这里咱们创立了一个类,含有 name 和 dept 两个参数,并且含有一个静态方法 fun 和一个办法 getName。

2.2 通过继承实现子类

应用 extends 实现继承 进行比拟:

//ES6
class Manager extends Employee {constructor(name, dept, reports) {super(name, dept)
    this.reports = reports
  }
}

这里咱们通过继承父类 Employee 创立了子类Manager,比父类多一个 reports 的属性,其余全副继承自父类。

3. 横向、纵向比拟

传统的 OO 语言(java,c++ 等等),都蕴含例如类、构造函数、继承、静态方法等等。他们通过这些来实现面向对象的性能,那么 JavaScript 是如何做的呢?

3.1 JavaScript 和 Java 进行横向比拟(以 Java 为例)

1. 类的概念(Class):

  • JavaScript 同 java 相似,都采纳了 class 来申明一个类。

2. 构造函数(constructor):

  • JavaScript 应用 constructor 办法当作构造函数,而 java 采纳类名作为构造函数。

3. 子类(extends):

  • JavaScript 同 java 统一,都应用 extends 来继承。

4. 静态方法(static):

  • ES6 中 JavaScript 同 java 统一,应用 extends 创立子类天然就将父类的静态方法继承过去。ES5 则须要手动申明指向。

5. 类的属性(int、double、String等):

  • JavaScript 得益于类型主动推断,不须要显示的申明类的属性。

3.2 ES6 和 ES5 的纵向比拟

咱们察看上面 ES5 和 ES6 两种形式创立父类和父类,应用 class 创立子类在逻辑上比 ES5 的办法更加清晰。

首先咱们比拟一下创立父类的形式:

再比拟子类 Manager,应用extends 继承创立的子类 Manager 天然继承了其中的属性和办法(包含静态方法),然而 ES5 中实现继承,不仅须要通过 call 解决调用的问题,同时静态方法无奈间接继承,须要在子类中二次申明能力继承。

!

然而 Class 真的在所有中央都优于传统代码吗?其实也不见得,在很多场合下如果只是单纯想应用一次该对象,为何肯定要形象出类来呢?应用字面量对象是不是更加好一些。

// 字面量对象
let person = {
  name: 'Jason',
  age: 18,
  adress: 'hangzhou',
  phone: '10086',
  getPhone: function () {return this.phone},
}

4. JavaScrpit 是如何实现 Class 的

咱们都晓得 ES5 中实现类的办法是通过原型链来实现的(详解 JavaScript 原型链),咱们应用 ES5 的写法,实现一个 Employee 的实例:

//ES5
let employ = new Employee(1, 2)
employ.__proto__.constructor === Employee //true
employ.__proto__ === Employee.prototype //true
Employee.prototype.constructor === Employee //true

这是没有问题的,__proto__指针指向构造函数的原型,咱们用 ES6 的 class 再来判断一遍:

//ES6 应用 class
let employ = new Employee(1, 2)
employ.__proto__.constructor === Employee //true
employ.__proto__ === Employee.prototype //true
Employee.prototype.constructor === Employee //true

两者的后果是雷同的!只不过应用函数创立的对象,__proto__指针指向构造函数,应用 class 关键字创立的对象,__proto__指针指向类。

咱们再来看这串代码:

console.log(typeof Employee) //function

咱们将 class 放入,居然返回的是 function,也就是 class 关键字实质上还是一个函数,应用 class 创立进去的类还是基于函数和原型链。

5. Class 关键字的限度

既然实质上 Class 依然是一个函数,他做的事件又是将 ES5 的写法更加精简,那么天然就会带来一些限度。

5.1 灵活性

假如当初有一个需要,在一个 Manager 对象中退出一个办法,在任何中央只有应用 ES5 的办法只须要在 prototype 上退出办法即可

//ES5
let manager1 = new Manager(1, 2, 3)
manager1.prototype.FunctionName = function () {/* 写本人的逻辑 */}

那么应用 class 该怎么办呢?class则肯定要在类中退出该办法。

//ES6
class Manager extends Employee {constructor(name, dept, reports) {super(name, dept)
    this.reports = reports
  }
  FunctionName() {/* 写本人的逻辑 */}
}

5.2 类申明不可晋升

函数申明具备可晋升性,尽管类实质上是函数,然而类的申明却不可晋升,也就是说你肯定要先申明类,能力创建对象。

let a = new ES6_Practice() // 报错
let b = new ES5_Practice() // 胜利
class ES6_Practice {}
function ES5_Practice() {}

5.3 无奈重写类

当咱们在特定时刻想要重写某个函数办法,只须要从新定义方法即可,然而类却无奈重写,如果呈现两个雷同的类名,则会报错语法错误(SyntaxError)。

class ES6_Practice{
}
class ES6_Practice{   // 报错 SyntaxError
    console.log("new class");
}
function ES5_Practice(){}
function ES5_Practice(){    // 没问题, 重写胜利
  console.log("new function");
}

6. 总结

ES6 中的关键字 Class 实质上还是通过原型链和函数做的,相比于应用 ES5 写法,Class给咱们提供了一种写法更加不便、逻辑更加清晰的办法去实现类。然而更加灵便、不便同时也会带来一些限度,咱们在写代码的时候也要留神一下这些限度。

也就如 TC39 在 ES6 提案上所说的:

it’s to provide a terse and declarative surface for those semantics so that programmer intent is expressed instead of the underlying imperative machinery 心愿程序员通过 Class 关键字分明的表白出他们想要的货色,让他们的想法得以表白,而不是还要思考底层的机制。

参考内容

Stack Overflow 对于 Class 关键字的探讨

GitHub 上 TC39 的 ES6 提案库

2016 年 ES6 中对于 Class 的提案

ES6 新增关键字 -MDN

JavaScript2.0 草案

类公有域 MDN

Java-wiki

JavaScript 中 7 中设计模式

JavaScript 深刻之从原型到原型链

OO 语言 -wiki

退出移动版