ES5以及以前的版本,没有类的概念,可是聪明的JavaScript开发者,为了实现面向对象,建立了特殊的近类结构。java
ES5中建立类的方法:新建一个构造函数,定义一个方法而且赋值给构造函数的原型。react
'use strict'; //新建构造函数,默认大写字母开头 function Person(name) { this.name = name; } //定义一个方法而且赋值给构造函数的原型 Person.prototype.sayName = function () { return this.name; }; var p = new Person('eryue'); console.log(p.sayName() // eryue );
ES6实现类很是简单,只须要类声明。推荐 babel在线测试ES6 测试下面的代码。segmentfault
若是你学过java,那么必定会很是熟悉这种声明类的方式。babel
class Person { //新建构造函数 constructor(name) { this.name = name //私有属性 } //定义一个方法而且赋值给构造函数的原型 sayName() { return this.name } } let p = new Person('eryue') console.log(p.sayName()) // eryue
和ES5中使用构造函数不一样的是,在ES6中,咱们将原型的实现写在了类中,但本质上仍是同样的,都是须要新建一个类名,而后实现构造函数,再实现原型方法。函数
私有属性:在class中实现私有属性,只须要在构造方法中定义this.xx = xx。测试
一、函数声明能够被提高,类声明不能提高。ui
二、类声明中的代码自动强行运行在严格模式下。this
三、类中的全部方法都是不可枚举的,而自定义类型中,能够经过Object.defineProperty()手工指定不可枚举属性。lua
四、每一个类都有一个[[construct]]的方法。prototype
五、只能使用new来调用类的构造函数。
六、不能在类中修改类名。
类有2种表现形式:声明式和表达式。
//声明式 class B { constructor() {} } //匿名表达式 let A = class { constructor() {} } //命名表达式,B能够在外部使用,而B1只能在内部使用 let B = class B1 { constructor() {} }
JavaScript函数是一等公民,类也设计成一等公民。
一、能够将类做为参数传入函数。
//新建一个类 let A = class { sayName() { return 'eryue' } } //该函数返回一个类的实例 function test(classA) { return new classA() } //给test函数传入A let t = test(A) console.log(t.sayName()) // eryue
二、经过当即调用类构造函数能够建立单例。
let a = new class { constructor(name) { this.name = name } sayName() { return this.name } }('eryue') console.log(a.sayName()) // eryue
类支持在原型上定义访问器属性。
class A { constructor(state) { this.state = state } // 建立getter get myName() { return this.state.name } // 建立setter set myName(name) { this.state.name = name } } // 获取指定对象的自身属性描述符。自身属性描述符是指直接在对象上定义(而非从对象的原型继承)的描述符。 let desriptor = Object.getOwnPropertyDescriptor(A.prototype, "myName") console.log("get" in desriptor) // true console.log(desriptor.enumerable) // false 不可枚举
可计算成员是指使用方括号包裹一个表达式,以下面定义了一个变量m,而后使用[m]设置为类A的原型方法。
let m = "sayName" class A { constructor(name) { this.name = name } [m]() { return this.name } } let a = new A("eryue") console.log(a.sayName()) // eryue
回顾一下上一章讲的生成器,生成器是一个返回迭代器的函数。在类中,咱们也可使用生成器方法。
class A { *printId() { yield 1; yield 2; yield 3; } } let a = new A() console.log(a.printId().next()) // {done: false, value: 1} console.log(a.printId().next()) // {done: false, value: 2} console.log(a.printId().next()) // {done: false, value: 3}
这个写法颇有趣,咱们新增一个原型方法稍微改动一下。
class A { *printId() { yield 1; yield 2; yield 3; } render() { //从render方法访问printId,很熟悉吧,这就是react中常常用到的写法。 return this.printId() } } let a = new A() console.log(a.render().next()) // {done: false, value: 1}
静态成员是指在方法名或属性名前面加上static关键字,和普通方法不同的是,static修饰的方法不能在实例中访问,只能在类中直接访问。
class A { constructor(name) { this.name = name } static create(name) { return new A(name) } } let a = A.create("eryue") console.log(a.name) // eryue let t = new A() console.log(t.create("eryue")) // t.create is not a function
咱们在写react的时候,自定义的组件会继承React.Component。
class A extends Component { constructor(props){ super(props) } }
A叫作派生类,在派生类中,若是使用了构造方法,就必须使用super()。
class Component { constructor([a, b] = props) { this.a = a this.b = b } add() { return this.a + this.b } } class T extends Component { constructor(props) { super(props) } } let t = new T([2, 3]) console.log(t.add()) // 5
关于super使用的几点要求:
一、只能够在派生类中使用super。派生类是指继承自其它类的新类。
二、在构造函数中访问this以前要调用super(),负责初始化this。
class T extends Component { constructor(props) { this.name = 1 // 错误,必须先写super() super(props) } }
三、若是不想调用super,可让类的构造函数返回一个对象。
咱们能够在继承的类中重写父类的方法。
class Component { constructor([a, b] = props) { this.a = a this.b = b } //父类的add方法,求和 add() { return this.a + this.b } } class T extends Component { constructor(props) { super(props) } //重写add方法,求积 add() { return this.a * this.b } } let t = new T([2, 3]) console.log(t.add()) // 6
父类中的静态成员,也能够继承到派生类中。静态成员继承只能经过派生类访问,不能经过派生类的实例访问。
class Component { constructor([a, b] = props) { this.a = a this.b = b } static printSum([a, b] = props) { return a + b } } class T extends Component { constructor(props) { super(props) } } console.log(T.printSum([2, 3])) // 5
很好理解,就是指父类能够是一个表达式。
有些牛逼的人以为使用内建的Array不够爽,就但愿ECMA提供一种继承内建对象的方法,而后那帮大神们就把这个功能添加到class中了。
class MyArray extends Array { } let colors = new Array() colors[0] = "1" console.log(colors) // [1]
该用法我尚未接触过,目前只知道在内建对象中使用了该方法,若是在类中调用this.constructor,使用Symbol.species可让派生类重写返回类型。
new.target一般表示当前的构造函数名。一般咱们使用new.target来阻止直接实例化基类,下面是这个例子的实现。
class A { constructor() { //若是当前的new.target为A类,就抛出异常 if (new.target === A) { throw new Error("error haha") } } } let a = new A() console.log(a) // error haha
本章只有一个知识点,那就是class的使用,最开始的声明class,到后面的继承派生类,都是很是经常使用的写法,还有静态成员的使用。
若是上面的那些例子你练习的不够爽,或许你该找个react基础demo简单的使用class来练练手了。