本文是 ES6
系列的第四篇,能够在 这里 查看 往期全部内容git
这篇文章主要记录了一些 class
相关的内容,都是咱们平常开发中可能会遇到的知识点es6
若是文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过github
如下↓web
ES6
以前,咱们生成实例对象的方法都是经过构造函数编程
function Person(name) { this.name = name } Person.prototype.say = function() { console.log(this.name) } var p = new Person('游荡de蝌蚪')
ES6
引入了 类
的概念,经过 class
关键字来定义。上面的代码就能够这样改写segmentfault
class Person { constructor(name) { this.name = name } say() { console.log(this.name) } } let p = new Person('游荡de蝌蚪')
class
的这种写法更接近传统语言,不管是对某个属性设置存储函数和取值函数,仍是实现继承,都要更加清晰和方便微信
类的本质是一个函数,类自身指向的就是构造函数
class Person {} typeof Person // function Person.prototype.constructor == Person // true
ES6
的 class
能够看做只是一个语法糖,它的绝大部分功能,ES5
均可以作到,新的 class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法babel
类的构造方法 constructor
对应的就是构造函数,定义在类中的方法都定义在类的 prototype
属性上面函数
class Person { constructor(){}, say() {}, run() {} ... } // 等同于 Person.prototype = { constructor(){}, say(){}, run(){} ... } let p = new Person() p.say == Person.prototype.say // true
console.log(Person) class Person {} // Uncaught ReferenceError: // Cannot access 'Person' before initialization
let Person = {} class Person {} // Uncaught SyntaxError: // Identifier 'Person' has already been declared
constructor
是类的默认方法,就算不定义,也会默认添加一个空的 constructor
new
关键字初始化,不然会报错class Person {} let p1 = new Person() let p2 = new Person() p1.__proto__ == p2.__proto__ //true
prototype
默认不可重写class Person {} Object.getOwnPropertyDescriptor(Person, 'prototype') /* configurable: false enumerable: false value: {constructor: ƒ} writable: false */
class Person { static say() { console.log('Hello') } }
class
中若是一个方法前添加了 static
关键字,那么就表示这个方法是静态方法。它不能被实例继承,只能经过类来调用学习
let p = new Person() p.say() // Uncaught TypeError: p.say is not a function Person.say() // Hello
须要注意的是:父类的静态方法,能够被子类继承
class Tadpole extends Person {} Tadpole.say() // Hello
所谓静态属性,就是类自己的属性,也就是说属性不能经过添加在 this
上的方式定义
// 属性不能定义在 this 上面,会被实例继承 class Person { constructor(name) { this.name = name } }
ES6
明确规定,Class
内部只有静态方法,没有静态属性
通常状况下,咱们实现静态属性的方式就是直接将属性添加到类上面:
Person.age = 18
可也以用一种变通的方式实现:
// 经过 static 静态方法与 get 方式的结合 class Person { static get age() { return 18 } }
类的静态属性和静态方法的表现基本一致:不能被实例继承,只能经过类来使用
提案 提供了一种类静态属性的另外一种方式,也是使用 static
关键字
class Person { static name = 18 }
所谓私有,通常须要具有如下特征:
class
内部访问,不能在外部使用ES6
并无提供 class
的私有属性及方法的实现方式,可是咱们能够经过如下几种方式来约定
_
,可是这种方式不是很保险,由于在类的外部仍是能够访问到这个方法class Person { // 公有方法 fn(age) { this.age = age } // 私有方法 _foo(age){ return this.age = age } }
this
创造出一个相对封闭的空间class Person{ foo(age) { bar.call(this, age) } } function bar(age) { return this.age = age }
提案 提供了一种实现 class
私有属性的方式:使用 #
关键字
class Person { #age = 18 }
若是咱们在外部使用这个属性就会报错
let p = new Person() Person.#age p.#age // Uncaught SyntaxError: // Private field '#age' must be declared in an enclosing class
另外,私有属性也支持 getter
和 setter
的方式以及静态 static
的方式
class Person { #age = 18 get #x() { return #age } set #x(value) { this.#age = value } static #say() { console.log(#age) } }
在 class
出现以前,咱们通常都会使用原型以及构造函数的方式实现继承,更多实现继承的方式参考 JavaScript中的继承
类的继承也是经过原型实现的
ES5
的继承,实质是先创造子类的实例对象this
,而后再将父类的方法添加到this
上面
ES6
的继承,实质是先将父类实例对象的属性和方法,加到this
上面(因此必须先调用super
方法),而后再用子类的构造函数修改this
class
经过extends
关键字实现继承
经过 extends
关键字,子类将继承父类的全部属性和方法
class Person {} class Tadpole extends Person {}
extends
关键字后面不只能够跟类,也能够是表达式
function Person(){ return class { say(){ alert('Hello') } } } class Tadpole extends Person(){} new Tadpole().say() // Hello
extends
关键字后面还能够跟任何具备 prototype
属性的函数(这个特性可让咱们很轻松的复制一个原生构造函数,好比 Object
)
function Fn() { this.name = 'tadpole' } // 注意,这里 constructor 的指向变了 Fn.prototype = { say() { console.log('My name is tadpole') } } class Tadpole extends Fn {} let t = new Tadpole() t.name // tadpole t.say() // My name is tadpole
子类经过继承会获取父类的全部属性和方法,因此下面的写法能够获得正确的结果
class Person { constructor() { this.name = '游荡de蝌蚪' } } class Tadpole extends Person{} let t = new Tadpole() t.name // 游荡de蝌蚪
可是,若是咱们在子类中定义了 constructor
属性,结果就是报错
class Tadpole extends Person { constructor(){} } let t = new Tadpole() // Must call super constructor in derived class before accessing 'this' or returning from derived constructor
若是咱们想要在子类中定义 constructor
属性,那么就必须调用 super
方法
// 正常 class Tadpole extends Person { constructor(){ super() } } let t = new Tadpole()
super表明了父类的构造函数,返回的是子类的实例,至关于 Person.prototype.constructor.call(this)
因此,上面代码中 super()
的做用实际上就是将 this
添加到当前类,而且返回
super
有两种使用方式:
super()
只能用在子类的构造函数之中,用在其余地方就会报错
super
指向父类的原型对象,因此定义在父类实例上的方法或属性,没法经过 super
调用)class Person { constructor() { this.name = '游荡de蝌蚪' } say() { console.log('My name is' + this.name) } } class Tadpole extends Person { constructor() { super() console.log(super.say()) // My name is 游荡de蝌蚪 console.log(super.name) // undefined } }
class Person { constructor() { this.name = '游荡de蝌蚪' } say() { console.log('My name is' + this.name) } static say() { console.log('My name in tadpole') } } class Tadpole extends Person { static say() { super.say() } say() { super.say() } } Person.say() // My name is tadpole Tadpole.say() // My name is tadpole let t = new Tadpole() t.say() // My name is 游荡de蝌蚪
this
,默认指向类的实例class Person { say() { this.run() } run() { console.log('Run!') } }
this
关键字,这个 this
指的是类,而不是实例class Person { static say() { console.log(this) // Person } }
constructor
中调用 super()
以后才能使用 this
class
中默认使用严格模式,若是将其中的方法单独调用,那么方法中的 this
指向 undefined
(默认指向全局对象)class
的出现为咱们的编程提供了不少便利,可是 class
自己也存在一些问题
class
,居然还只是 语法糖
,你说气人不气人prototype
,因此 class
也存在原型所具备的一些问题,好比修改父类上面的属性可能会影响到全部子类(固然,私有属性的出现仍是解决了一些问题)class
,好比那个啥啥啥,固然了也有解决的方式:babel
尽管 class
仍是存在些许问题,但它必定会愈来愈丰富...
以上就是关于 class
的所有内容,但愿对看到的小伙伴有些许帮助
大胆地在你的项目中使用 class
吧,相信你绝对会爱上它
感兴趣的小伙伴能够 点击这里 ,也能够扫描下方二维码关注个人微信公众号,查看往期更多内容,欢迎 star
关注