小胖墩er 小胖墩er
首页
  • 前端文章

    • JavaScript
    • Vue
    • ES6
    • Git
  • Vue
  • React
  • HTML
  • CSS
  • 工具类
  • GitHub技巧
  • 博客搭建
  • 友情链接
💖关于
💻收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

小胖墩er

Better later than never.
首页
  • 前端文章

    • JavaScript
    • Vue
    • ES6
    • Git
  • Vue
  • React
  • HTML
  • CSS
  • 工具类
  • GitHub技巧
  • 博客搭建
  • 友情链接
💖关于
💻收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaScript文章

  • Vue文章

  • ES6文章

    • 基本概念的使用
    • 函数
    • Class
      • 介绍
      • 基本语法
      • constructor 方法
      • 实例属性
      • 静态方法
      • 静态属性
      • 私有属性
      • 类的继承
      • super的属性
    • 利用ES6的class类继承实现绚丽小球效果
    • 模块
    • ES6新增方法
    • Promise
  • Git

  • axios

  • Webpack

  • 语言框架
  • ES6文章
小胖墩er
2021-08-09

Class

# 介绍

js是一个脚本语言没有像强语言一样拥有类这样一个概念,在ES6之前创建一个实例对象都使用的是构造函数的方法。ES6引入了class的概念,通过 class 关键字定义类,作为对象的模板。Class可以看作一个语法糖所以他的本质就是一个function。class模板写法让对象原型的写法更加清晰、更像面向对象编程的语法。

# 基本语法

语法:

  1. 通过class关键声明的类可以认为是构造函数的另一种写法,同样使用 new 关键字创建类实例对象

  2. 在前端开发中我们约定类名首字母大写。类可以匿名也可具名

class App {
    // 这是一个具名类
}

let app = new App() // 创建 App 类的实例对象 

let Demo = class {
    // 这是一个匿名类
}

let demo = new Demo() // 创建 Demo 类的实例对象 
1
2
3
4
5
6
7
8
9
10
11
  1. 构造函数的prototype属性在class依然存在
 class App {
   sayHello () {
       console.log('你好我是App')
   }

   sayGoodbye () {
       console.log('再见我是App')
   }
}
 let app = new App()
 
 app.sayHello()   //   '你好我是App'
 app.sayGoodbye()   //  '再见我是App'    
 /*
 等价于
 class App () {}
 App.prototype = { 
       sayHello () {
           console.log('你好我是App')
       }

       sayGoodbye () {
           console.log('再见我是App')
       }
 }
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

注意

  1. 我们打印上面的App类会发现,类中的所有方法全部都存储在类的prototype对象上面(即类的所有方法都是原型方法)
  2. class支持动态属性
let key = 'sayHello'
class App {
    [key]() {
       console.log('你好我是App')
    }
}
// App.prototype.sayHello()
// 函数也可以使用动态函数名
function [key] () {
    
}
//等价于 function sayHello () { }
1
2
3
4
5
6
7
8
9
10
11
12
  1. 类内部定义的属性都是不可枚举的
 class App {
   sayHello () {
       console.log('你好我是App')
   }

   sayGoodbye () {
       console.log('再见我是App')
   }
}
     
for(key in App.prototype) { 
    // 这里不会被执行
    console.log(key)
}

console.log(App.prototype)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# constructor 方法

概念: constructor方法是类的构造函数,也是类的默认方法。通过new关键字创建类的实例时,会自动调用 constructor 方法

经典面试题: new关键字到底做了什么? 可以好好思考思考了。

提示

  1. 一个类必须由constructor方法。如果创建class时没有显示定义constructor方法,class会默认的隐式添加一个空的constructor方法

  2. constructor函数会隐式默认的返回当前实例对象(即this)。开发人员可以显示返回另一个对象这样当前class实例化后生成的就是 constructor函数 返回的新对象

class Demo {
    say() {
        console.log(123)
    }
}


 class App {
   constructor() {
       return new Demo()
   }

   sayHello () {
       console.log('你好我是App', this)
   }

   sayGoodbye () {
       console.log('再见我是App')
   }
}
     
 let app = new App()

console.log(app) // 这里的app 是 Demo 的实例对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  1. class 只允许使用new关键字创建实例对象, 而不允许像构造函数一样直接调用。这一特性是他与构造函数的主要区别
class App {
    sayHello() {
        console.log('你好我是App', this)
    }

    sayGoodbye() {
        console.log('再见我是App')
    }
}

App() // Error  class不可在没有new关键字情况下直接调用
1
2
3
4
5
6
7
8
9
10
11

# 实例属性

概念: 通过class塑造的实例对象自身的属性(及this的属性)

语法:

方法一: 在构造函数 constructor构造函数中同this设置

 class App {
     constructor(name, age) {
        // 这里的this就是实例对象自身
        this.name = name
        this.age = age 
    }
}

let app = new App('小明', 12)
1
2
3
4
5
6
7
8
9

方法二: 直接写在class中的属性 属性名 = 属性值

 class App {
     // 可以将所有的实例属性写在class的顶部,可以直观地看到当前实例有哪些属性
    a = 1
    b = function() {}         
}
1
2
3
4
5

方法三: 使用类的get/set创建实例属性 概念: 与ES5 一样class可以在内部使用get 和 set 关键字对某个属性设置 get函数和set函数,拦截该属性的存取行为

语法: 下面实现了一个类似Vue数据发生改变对应DOM更新的案例

class ObsVue {

    constructor(selecter, count) {
        this.html = document.getElementById(selecter)
        this._count = count
        this.inital()
        this.html.onclick = this.addCount.bind(this)
    }
    // 设置赋值拦截函数 当给this.count赋值时该方法会被调用
    set count(value) {
        console.log('每次给this.count 赋值都会触发set方法',value)
        this._count = value
        // 更新UI
        this.html.innerHTML = `你点击了我${this.count}次`
    }
  // 设置取值拦截函数 当获取this.count时该方法会被调用
    get count() {
        // 每次获取this.count属性值 都会调用该函数
        // get 方法一定要有return值,他的返回值就是当前属性的值
        return this._count
    }

    inital() {
        this.html.innerHTML = `你点击了我${this.count}次`
    }

    addCount() {
        console.log(this)
        this.count++
    }

}

let obs = new ObsVue('app', 0)

obs.count = 17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 静态方法

概念: 不会被实例对象所继承的方法,只能通过class自身调用

语法: 使用关键字static 声明

class App {
   test () {
         console.log('原型方法')
   }

   static demo () {
         console.log('静态方法')
   }

}

let app = new App()

console.log(app)

App.demo() // 只能通过类自身调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

提示

  1. 静态方法内部this指向构造函数自身,不是类的实例

  2. 静态可以被子类所继承

# 静态属性

概念: 不会被实例对象继承的属性就是静态属性,在class中只有静态方法没有静态属性。后来有一个提案提出使用static 关键字声明静态属性

语法:

 class App {
     static val = '静态属性'
}

console.log(App.val) // '静态属性'
1
2
3
4
5

# 私有属性

概念: 在js中一直不存在真正的私有属性。以往实现私有属性的方法一共有以下几种:

方法一: 属性名前加下划线,表示该属性是一个私有属性,但是这种方法是不保险的。即使加了下划线该属性在外部依然可以调用

 class App {
     _val = '私有属性'
}
1
2
3

方法二: 使用模块化

class App {
    constructor () {
        bar.call(this)
    }
    
}

function bar() {
    this.val = '私有属性'
}
1
2
3
4
5
6
7
8
9
10

方法三: Symbol

let a = Symbol('val')
class App {
    constructor () {
       this[a] = '私有属性'
    }
}
1
2
3
4
5
6

方法四: ES2020 中提案 用#开头声明私有属性

class App {
      // 私有属性只能在constructor外部声明
       #age = 14

       constructor() {
           this.name = '123'
           this.#age = 18
       }

       sayHello() {
           console.log(this.name, this.#age)
       }
}

let app = new App()

app.sayHello() // "123" 18

app.#age // Error 私有属性不能再外部调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 类的继承

概念: class 可以通过 extend 关键字实现类的继承

语法:

 class Animal {
    constructor() {
        this.type = '动物'
    }

    static show() {
        console.log('我是动物的静态方法')
    }

    static val = 10086

    sayHello() {
        console.log('hello')
    }
}

class Cat extends Animal {

}

let cat = new Cat()

console.log(cat)

console.log(cat.type)

cat.sayHello()

Cat.show()

console.log(Cat.val) 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

提示

1. 使用了类的继承的子类在其constructor函数中一定要调用一个super函数,否则新建实例会报错。


2. 因为在类的继承中子类的this对象必须调用父类constructor完成塑造,得到父类相同的属性和方法,然后进行加工返回子类的this,子类的this再加上子类自身的实例属性方法。super其实就是父类的constructor方法。如果不在子类构造函数内部调用super,子类就没有this对象。


3. 注意如果子类没有显示声明constructor函数,ES6会自动隐式创建constructor函数并在其内部调用super方法。如果你的子类constructor中不需要设置实例属性推荐隐式创建constructor函数
1
2
3
4
5
6
7
class Cat extends Animal {
    constructor() {
       super()    
    }
}

class Cat extends Animal {
   // 不显示声明 等价于上面的代码,
   // 如果constructor中不需要做任何初始化操作 推荐不要显示声明constructor
}
1
2
3
4
5
6
7
8
9
10

# super的属性

概念: super就是父类构造函数,所以super与父类的构造函数接收同样参数,在使用类的继承时一定要记得给super传递参数,即 如果 A 类继承了 B 类,且 A 类中写了构造器,那么A类构造器中的super是必须要调用的

语法:

class Animal {
    constructor(x,y) {
        this.x = x
        this.y = y
    }
}
class Cat extends Animal {
    constructor(x,y,detail) {
        super(x,y)
        this.detail = detail
    }
}

let cat = new Cat(1,2,'cat')

cat.x // 1
cat.y // 2
cat.detail // 'cat'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

提示

使用...语法可以简化 super 传参问题

class Animal {
    constructor(x,y) {
        this.x = x
        this.y = y
    }
}
class Cat extends Animal {
    constructor(detail, ...props) {
        super(...props)
        this.detail = detail
    }
}

let cat = new Cat('猫',1,3)
console.log(cat)
cat.detail // 猫
cat.x // 1
cat.y // 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在线编辑 (opens new window)
#ES6
上次更新: 2021/11/14, 07:48:46
函数
利用ES6的class类继承实现绚丽小球效果

← 函数 利用ES6的class类继承实现绚丽小球效果→

最近更新
01
毛玻璃效果
11-23
02
svg基本绘制
11-23
03
滑动登录界面
11-23
更多文章>
🖥️

© 2021 小胖墩er 💌 粤ICP备2021158933号 🛀 Theme by 💝 Vdoing

  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×