参考链接: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 面向对象编程的一个较大的好处之一 是我们不必理解其内部实现 依然可以很好的去进行编程开发
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。