ES6之class

41次阅读

共计 5218 个字符,预计需要花费 14 分钟才能阅读完成。

参考链接:https://segmentfault.com/a/11…
参考链接:https://segmentfault.com/a/11…

什么是类


在面向对象的编程中 类是一个用于创建对象 为状态(成员变量) 和行为实现(成员函数或方法)提供初始值的可扩展程序代码模板

在实际开发中,我们往往需要创建很多相同类型的对象,如用户、商品或其他对象。我们知道,通过 new 一个 function 可以创建一个对象,但在现代的 JavaScript 里,有一个更高级的“类”结构,对于面向对象编程提供了一些很不错的特性。

基本语法

class MyClass{constructor(){}
       method1(){}
       method2(){}
       method3(){}
     }

然后通过 new MyClass 来创建一个拥有以上方法的对象实例 与此同时 通过 new 操作符 构造方法(constructor)是被自动调用的,这意味着在构造方法中我们可以做一些初始化的工作

class User{constructor(name){this.name = name}
      showInfo(){alert(this.name)
      }
    }
  var user = new User('WhiteCode') // 当 new 的时候 创建了一个新的对象  构造方法通过给定的参数运行,并为其分配 this.name
  user.showInfo()
  // 类方法之间是没有逗号的

类是函数的一种

class User{ // 创建一个名为 User 的函数 该函数将成为类声明的结果
      constructor(name){this.name = name}
      showInfo(){ // 在 User.prototype 中储存所有方法 例如 showInfo
      // 对于新对象 当我们调用一个方法的时候,它就是从原型中获取 因此新的 User 对象就可以访问到类方法了
        alert (this.name)
      }
    }
    alert(typeof User)//function
    alert(User === User.prototype.constructor) //true
    alert(User.prototype.showInfo)//showInfo(){  alert (this.name) }
      // there are exactly two methods in the prototype
    alert(Object.getOwnPropertyNames(User.prototype)) //constructor,showInfo

ES5 与 ES6 的比较

es5
function People(name,age){
      this.name = name
      this.age = age
    }
    People.prototype.say = function(){console.log("hello")
    }
    People.see = function(){alert("how are you")
    }
    var a = new People()
    a.say()
    
    
    . 通过 es6 的 class 声明类
    class People{constructor(name,age){
      this.name = name
      this.age = age
    }
    see(){ alert('how are you')}
    say(){console.log('hello')
    }
  }
    var a = new People()
    a.say()

①People 是一个类,也是一个函数;②constructor 是一个对象指向的是 People 函数,该函数还挂了 name 和 age 属性;③将 say 函数挂载 People 的原型上。

大多数 JavaScript 引擎中的类构造函数的字符串表示形式都以“class …”开头。

类方法是不可枚举的。对于原型中的所有方法,类定义将 enumerable 标志设置为 false。类总是使用严格模式的。这意味着类构造中的所有代码都自动处于严格模式。

与常规函数不同,如果没有 new,则无法调用类构造函数

class User{constructor(){}}
  alert(typeof User);//function
  User();// Error: Class constructor User cannot be invoked without 'new'

就像函数一样,类可以在另一个表达式中定义,传递,返回,分配等。

let User = class{  // 与命名函数表达式类似,类表达式可能有也可能没有名称
      showInfo(){alert('hello')
      }
    }
    new User().showInfo()

我们可以 ’ 按需 ’ 动态创建类

function makeClass(rass){
    // declare a class and return it
    return class{showInfo(){alert(rass)
      }
    }
  }
  // Create a new class
  let User = makeClass('hello')
  new User().showInfo()//hello

Getters/Setters

// 类可能包括 getter/setter, 生成器,计算属性等 这里通过使用 get/set 来实现 user.name
  class User{constructor(name){this._name =name}
    get name(){return this._name}
    set name(value){if(value.length<4){alert('名字长度不够')
        return
      }
      this._name = name
    }
  }
  let user = new User('biubiu')
  alert(user.name)
  user = new User()// 名字长度不够 '

在 User 的原型对象中,通过类声明创建 get/set

Object.defineProperties(User.prototype,{
    name:{get(){return this._name},
      set(name){// ...}
    }
  })
class User {
      name = "see"
      sayHi(){alert(`hello,${this.name}!`)
      }
    }
    new User().sayHi()
// 该属性未放入 User 的原型中 相反 它是由 new 创建的 分别为每一个对象创建,因此该属性永远不会在同一个类的不同的对象之间共享

在 Class 内部可以使用 get 和 set 关键字

对某个属性设置存值函数和取值函数,拦截该属性的存取行为

class MyClass {constructor(){// ...}
      get prop(){return 'getter';}
      set prop(value){console.log('setter:'+ value)
      }
    }
     let inst = new MyClass()
     inst.prop = 124  //setter:124
     var a = inst.prop
     console.log(a) //getter
    //  prop 属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了

存值函数和取值函数是设置在属性 descriptor 对象上的

class CustomHTMLElment {// 存值函数和取值函数是设置在属性 descriptor 对象上的
     constructor(element){this.element = element}
     get html(){return this.element.innerHTML}
     set html(value){this.element.innerHTML = value}
   }
  //  Object.getOwnPropertyDescriptor 如果指定的属性存在于对象上 则返回其属性描述符对象,否则返回 underfined
   var descriptor = Object.getOwnPropertyDescriptor(CustomHTMLElment.prototype,'html')
   console.log(descriptor) //{enumerable: false, configurable: true, get: ƒ, set: ƒ}
  //  存值函数和取值函数是定义在 html 属性的描述对象上面
  console.log('get' in descriptor)//true
  console.log('get' in descriptor)//true

Es6 中 Class 私有和受保护的属性及方法

在 JavaScript 中,有两种类型的对象字段(属性和方法):

公共的:随处都可访问,它们包含外部接口,我们在开发中一直常用的也就是公共的属性和方法了
私有的:仅在类的内部可访问,主要用于内部接口

class MBWCar{
     oilAmount = 0
     constructor(power){
       this.power = power
       alert(`Created a mbw-car,power: ${power}`)
     }
   }
   let mbwCar = new MBWCar(100)
   mbwCar.oilAmount = 200
  //  从上面的代码可以看出 oilAmount 与 power 这两个属性是公共的,我们可以在外部轻易的设置以及获取他们
  // 将 oilAmount 属性更改为 protected 以对其进行更多的控制

受保护的属性通常以下划线_为前缀
这不是在语言层面强制去执行,但咱们程序员之间有一个众所周知的惯例,即不应该从外部访问这些属性和方法
例如,我们不希望任何人将其设置为零以下。

class MBWCar{
    _oilAmount = 0
    constructor(power){this._power = power}
    set oilAmount(value){if (value<0) throw new Error('Negative oil')
      this._oilAmount = value
    }
    get oilAmount(){return  this._oilAmount}
  }
  let mbwCar = new MBWCar(100)
  mbwCar.oilAmount = -10 //Error Negative oil
  console.log(mbwCar)  // 现在访问受到控制,因此将油量设置为零以下将失败。

我们可以把 power 属性设置为只读属性 不可修改其值

class MBWCar{constructor(power){this._power = power}
      get power(){return this._power}
    }
    let mbwCar = new MBWCar(100)
    alert(`Power is: ${mbwCar.power}W`)
    mbwCar.power = 25//Error (no set)

getter/setter 方法

class Car{
      _oilMount = 0
      setOilMount(value){if(value<0)throw Error('Negative oil')
        this._oilMount = value
      }
      getOilMount(){return this._oilMount}
    }
    let car = new Car()
    car.setOilMount(100)
    alert(car.getOilMount())
//  受保护的属性是可以继承的
// 如果我们继承类 Car 扩展 Car 那么没有什么能够阻止我们从新的方法中访问 this._oilMount 或 this._power 属性  所以受保护的属性是可以继承的

私有字段

这是 js 新增的一个针对类属性的语法,js 引擎目前部分支持 需要进行 polyfilling
私有的私有字段与 #开头仅在类的内部可进行访问

class Car{
    #oilLimit = 100
    #checkOil(value){if(value>0) throw Error('Negative oil')
      if(value > this.#waterLimit) throw new Error('Too much oil')
    }
  }
  let car = new Car()
  car.#checkOil() //error
  car.#waterLimit = 1000 //Error

  class BWMCar extends Car{methods(){alert(this.#oilLimit) // Error: can only access from Car
    }
  }

私有字段不能通过 this[name]去访问

class User{sayHi(){
      let filedName = 'Darkcod'
      alert(`Hello,${this.filedName}`)
    }
  }
  new User().sayHi()

1 面向对象编程最重要的原则之一 - 从外部接口划分内部接口 这就涉及到属性和方法的可访问范围度
2 在面向对象的编程中,可通过 private protected public 来对类的属性和方法进行限制,例如你从你父亲那里继承了一些属性,但你父亲那里继承了一些属性 但你的父亲其他属性不想被你继承到等
3 在 javascript 中 受保护的属性和方法以_开头 私有的属性和方法名以 #开头
4 面向对象编程的一个较大的好处之一 是我们不必理解其内部实现 依然可以很好的去进行编程开发

正文完
 0