《深切明白ES6》笔记—— JavaScript中的类class(9)

ES5中的近类组织

ES5以及之前的版本,没有类的观点,然则智慧的JavaScript开发者,为了完成面向对象,建立了特别的近类组织。

ES5中建立类的要领:新建一个组织函数,定义一个要领而且赋值给组织函数的原型。

'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 class类

ES6完成类非常简朴,只须要类声明。引荐 babel在线测试ES6 测试下面的代码。

类声明

假如你学过java,那末一定会非常熟习这类声明类的体式格局。

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。

类声明和函数声明的区分和特性

1、函数声明能够被提拔,类声明不能提拔。

2、类声明中的代码自动强行运行在严厉形式下。

3、类中的一切要领都是不可枚举的,而自定义范例中,能够经由过程Object.defineProperty()手工指定不可枚举属性。

4、每一个类都有一个[[construct]]的要领。

5、只能运用new来挪用类的组织函数。

6、不能在类中修正类名。

类表达式

类有2种表现形式:声明式和表达式。

//声明式
class B {
  constructor() {}
}

//匿名表达式
let A = class {
  constructor() {}
}

//定名表达式,B能够在外部运用,而B1只能在内部运用
let B = class B1 {
  constructor() {}
}

类是一等国民

JavaScript函数是一等国民,类也设想成一等国民。

1、能够将类作为参数传入函数。

//新建一个类
let A = class {
  sayName() {
    return 'eryue'
  }
}
//该函数返回一个类的实例
function test(classA) {
  return new classA()
}
//给test函数传入A
let t = test(A)
console.log(t.sayName()) // eryue

2、经由过程马上挪用类组织函数能够建立单例。

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运用的几点请求:

1、只能够在派生类中运用super。派生类是指继续自别的类的新类。

2、在组织函数中接见this之前要挪用super(),担任初始化this。

class T extends Component {
  constructor(props) {
    this.name = 1 // 毛病,必需先写super()
    super(props)
  }
}

3、假如不想挪用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]

Symbol.species

该用法我还没有打仗过,现在只知道在内建对象中运用了该要领,假如在类中挪用this.constructor,运用Symbol.species能够让派生类重写返回范例。

在组织函数中运用new.target

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来练练手了。

=> 返回文章目次

    原文作者:二月
    原文地址: https://segmentfault.com/a/1190000010403659
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞