(二)面向对象
面向對象
- 搭建開發環境
- 初始化npm環境,npm init
- 安裝 webpack
- 啟動服務
- babel 解析 ES6
- 代碼如下
- 什么是面向對象
- 概念
- 三要素
- 繼承
- 封裝
- 多態
- 應用場景
- 為何要用面向對象
- 其他
- UML類圖
- 介紹
- 類圖
- 幾種關系
- demo
- 總結
- 總結
搭建開發環境
初始化npm環境,npm init
第一,下載安裝 nodejs ,完成后運行node -v和npm -v測試。
第二,找到一個目錄,運行npm init初始化(一路回車,然后會生成package.json文件),然后目錄下創建src文件夾。
第三,創建src/index.js,寫一句 JS 代碼,等待使用
安裝 webpack
先安裝 webpack 相關插件
npm install webpack webpack-cli --save-dev然后在根目錄創建webpack.dev.config.js,內容如下
module.exports = {entry: './src/index.js',output: {path: __dirname,filename: './release/bundle.js' // release 會自動創建} }修改package.json的scripts
"scripts": {"dev": "webpack --config ./webpack.dev.config.js --mode development" },然后控制臺運行npm run dev,可以看到生成了release/bundle.js
啟動服務
安裝插件npm install webpack-dev-server html-webpack-plugin --save-dev ,然后根目錄創建index.html
<!DOCTYPE html> <html> <head><meta charset="UTF-8"><title></title> </head> <body><p>前端設計模式</p> </body> </html>修改webpack.dev.config.js,修改為:
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {path: __dirname,filename: './release/bundle.js' // release 會自動創建},plugins: [new HtmlWebpackPlugin({template: './index.html' // bundle.js 會自動注入})],devServer: {contentBase: path.join(__dirname, "./release"), // 根目錄open: true, // 自動打開瀏覽器port: 9000 // 端口} }再次修改package.json的scripts
"scripts": {"dev": "webpack-dev-server --config ./webpack.dev.config.js --mode development" },然后再運行npm run dev,可以看到瀏覽器自動打開。并且,你修改src/index.js的源碼,瀏覽器會自動刷新。
babel 解析 ES6
安裝插件
npm install babel-core babel-loader babel-polyfill babel-preset-es2015 babel-preset-latest --save-dev創建.babelrc文件,內容如
{"presets": ["es2015", "latest"],"plugins": [] }修改webpack.dev.config.js文件內容,增加module
module: {rules: [{test: /\.js?$/,exclude: /(node_modules)/,loader: 'babel-loader'}] }然后修改src/index.js,寫點 ES6 的語法,:
class Person {constructor(name) {this.name = name}getName() {return this.name} }let p = new Person('雙越老師') console.log(p.getName())如然后運行npm run dev,即可看到效果。
結束。
代碼如下
//package.json {"name": "es6","version": "1.0.0","description": "","main": "index.js","scripts": {"dev": "webpack-dev-server --config ./webpack.dev.config.js --mode development"},"author": "","license": "ISC","devDependencies": {"babel-core": "^6.26.3","babel-loader": "^7.1.4","babel-plugin-transform-decorators-legacy": "^1.3.4","babel-polyfill": "^6.26.0","babel-preset-es2015": "^6.24.1","babel-preset-latest": "^6.24.1","html-webpack-plugin": "^3.2.0","webpack": "^4.8.3","webpack-cli": "^2.1.3","webpack-dev-server": "^3.1.4"},"dependencies": {"javascript-state-machine": "^3.0.1","jquery": "^3.3.1"} } //webpack.dev.config.js const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {path: __dirname,filename: './release/bundle.js' // release 會自動創建},plugins: [new HtmlWebpackPlugin({template: './index.html' // bundle.js 會自動注入})],devServer: {contentBase: path.join(__dirname, "./release"), // 根目錄open: true, // 自動打開瀏覽器port: 9000, // 端口proxy: {'/api/*': {target: 'http://localhost:8880'}}},module: {rules: [{test: /\.js?$/,exclude: /(node_modules)/,loader: 'babel-loader'}]} } //.babelrc {"presets": ["es2015", "latest"],"plugins": ["transform-decorators-legacy"] }什么是面向對象
面向對象,Object Oritented(簡稱 OO)是一種目前主流的編程思想,也是學習設計模式的前提,因為設計模式就是基于面向對象思想的。
概念
首先要有一個模板,然后通過模板可創建若干個實例,實例有屬性和方法。看演示:
// 類,即模板 class People {constructor(name, age) {this.name = namethis.age = age}eat() {alert(`${this.name} eat something`)}speak() {alert(`My name is ${this.name}, age ${this.age}`)} }// 創建實例 let zhang = new People('zhang', 20) zhang.eat() zhang.speak()// 創建實例 let wang = new People('wang', 21) wang.eat() wang.speak()三要素
- 繼承,子類繼承父類
- 封裝,數據的權限和保密
- 多態,同一接口不同實現
繼承
子類繼承父類的一些東西,子類的公共內容抽象到父類中,避免代碼的冗余
class People {constructor(name, age) {this.name = namethis.age = age}eat() {alert(`${this.name} eat something`)}speak() {alert(`My name is ${this.name}, age ${this.age}`)} }class Student extends People {constructor(name, age, number) {super(name, age)this.number = number}study() {alert(`${this.name} study`)} }let xiaoming = new Student('xiaoming', 10, 'A1') xiaoming.study() console.log(xiaoming.number) let xiaohong = new Student('xiaohong', 11, 'A2') xiaohong.study()上述代碼中,
- People是父類,是一種公共的抽離,不僅僅服務于Student
- 繼承的意義就在于將底層的、公共的屬性抽離出來,單獨存放,提高復用,極少冗余
封裝
封裝特性涉及到幾個關鍵字,用于規定屬性或者方法的開放程度
- public 開放性訪問
- protected 只有繼承的子類可訪問
- private 只有自身可訪問
這是 java 中最基本的知識,不過在 ES6 中不支持,而在 typescript 是支持的。以下代碼可在 http://www.typescriptlang.org/play/ 在線測試
// ts 代碼,放在在線解析器中解析為 es5 class People {nameageprotected weight // 定義 protected 屬性constructor(name, age) {this.name = namethis.age = agethis.weight = 120}eat() {alert(`${this.name} eat something`)}speak() {alert(`My name is ${this.name}, age ${this.age}`)} }class Student extends People {numberprivate girlfriend // 定義 private 屬性constructor(name, age, number) {super(name, age)this.number = numberthis.girlfriend = 'xiaoli'}study() {alert(`${this.name} study`)}getWeight() { alert(`${this.weight}`)} }let xiaoming = new Student('xiaoming', 10, 'A1') xiaoming.getWeight() // console.log(xiaoming.girlfriend) // 注意,編譯時會報錯,直接會編譯不通過!!!- 減少耦合,不該外露的不外露
- 利于數據、接口的權限管理
ES6 中不支持怎么辦?一般有一個不成為的約定,即以_開頭的屬性或者方法,都是私有的,其他的都是開放的,這樣即可按照約定分開public和private。另外,如果 ES6 要實現絕對的“私有”,就得用閉包了,但是閉包不會自動清理內存的,這一點就不如private專業了。再繼續思考一下,如果非要做成這種強制性的 private 效果,該怎么辦?
- 用閉包,但問題是:
- 理解復雜,學習成本高,不夠簡單
- 不符合面向對象思想,因為閉包的數據不是對象的某個屬性
- 無法清理內存
多態
同一個接口,不同表現(定義了一個接口,在子類中實現不同功能)
JS應用極少
需要結合java等語言的接口、重寫、重載等功能
多態即執行同樣的方法,不同對象會有不同表現。前端用的比較少,因為這個特性一般要結合接口、重載、重寫等 java 的特性去使用。舉個例子說明:
class People {constructor(name) {this.name = name}saySomething() {} } class A extends People {constructor(name) {super(name)}saySomething() {alert('I am A')} } class B extends People {constructor(name) {super(name)}saySomething() {alert('I am B')} } let a = new A('a') a.saySomething() let b = new B('b') b.saySomething()用 js 只能簡單演示,但是無法 100% 體現這種特性,用 java 的接口是最好的體現方式(如下兩點)。但是 js 無法體現,也就說明平時用不到,也就不詳細追究了。
- 類必須實現接口的方法
- 可以定義接口類型的變量,面向接口編程
多態的好處:保持子類的開放性和靈活性,面向接口編程。
應用場景
jQuery是一個class
$(‘p’)是jQuery的一個實例
jQuery 是面向對象的典型代表,執行$('p')其實就是創建了一個實例,可以模擬一下 jQuery 的源碼。
class jQuery {constructor(selector) {let slice = Array.prototype.slicelet dom = slice.call(document.querySelectorAll(selector))let len = dom ? dom.length : 0for (let i = 0; i < len; i++) {this[i] = dom[i]}this.length = lenthis.selector = selector || ''}append(node) {}addClass(name) {}html(data) {}// 此處省略若干 API } window.$ = function (selector) {return new jQuery(selector) }測試代碼
var $p = $('p') console.log($p) console.log($p.addClass)另外,React 和 vue 中用到的組件,也是面向對象的實例。面向對象無處不在,當你需要設計、開發一個功能的時候,一定要考慮面向對象。
為何要用面向對象
- 程序執行:順序、判斷、循環 — 結構化
- 面向對象 — 數據結構化
- 對于計算機,結構化的才是最簡單的
- 編程應該 簡單&抽象(抽象完以后才能簡單,簡單的前提是抽象好)
經過半個多世紀發展,現在程序執行上抽象出了三種執行方式 —— 順序、判斷、循環 ,你不要以為這是理所當然本來就有的,它是經過長久摸索才出來的。例如之前還有 goto 語句,后來因為過于繁瑣復雜,漸漸不再支持了。
列舉這個例子的用意是為了說明,編程應該變得簡單、有規律、結構化,而不是復雜、無章可循。程序中的數據也一樣,也應該是結構化的、有規律的,因此就有了面向對象。這句話如果你現在看不明白,不著急,后面的課程根據實例慢慢消化。
數據結構化的重要性:如 babel 解析 JS ,vue 解析模板 ,所以的編譯行為,都需要將字符串轉化為 AST(抽象語法樹,結構化數據),再執行接下來操作。
無論你理解與否,都要記住“編程應該 簡單 & 抽象”,這兩個詞看似矛盾,卻目的一樣。無論是面向對象還是設計模式,都是為了這個目的。
最后引用劉慈欣《球狀閃電》中的一句話 —— 早期的人們之所以沒有實現計算機,不是因為他們想的不夠復雜,而是因為想的不夠簡單,其實就 0 1 兩個數而已。
其他
關于 typescript 的補充:
- 強類型語言,類型判斷
- 屬性判斷,JS 中是大坑
- vue 源碼用了 flow 做類型判斷
- 做大型項目,多人協作,需要嚴格的標準規定,推薦使用 ts ;做小型臨時性項目,不推薦
UML類圖
介紹
UML - Unified Modeling Language - 統一建模語言,軟件工程(不僅是編程)中的任何設計都可以用它來表述,包含:
Unified Modeling Language - 統一建模語言
類圖,UML包含很多種圖,和本課相關的是類圖
關系,主要泛化和關聯
演示,代碼和類圖結合
- 用例圖
- 類圖
- 對象圖
- 順序圖
- 協作圖
- 狀態圖
- 活動圖
- 組件圖
- 配置圖
描述面向對象,重點介紹類圖。畫圖工具:
- https://www.processon.com/
- office visio
類圖
根據上一節的 demo 畫圖演示
幾種關系
- 泛化表示繼承
- 實現
- 關聯表示引用
- 聚合
- 組合
- 依賴
(畫圖演示)
demo
將之前的一個示例代碼換成 UML 類圖
class People {constructor(name,house) {this.name = namethis.house = house}saySomething() {} } class A extends People {constructor(name,house) {super(name,house)}saySomething() {alert('I am A')} } class B extends People {constructor(name,house) {super(name,house)}saySomething() {alert('I am B')} } class House {constructor(city) {this.city = city}showCity() {alert(`house in ${this.city}`)} } //測試 let aHouse = new House('北京') let a = new A('aaa',aHouse) console.log(a) //a 有房子 let b = new B('bbb') console.log(b) //b 無房子UML 圖的學習剛剛開始,以后每講到一個重要的設計模式,都會畫它的 UML 圖,并寫代碼。
總結
類圖,屬性、方法
關系,泛化、關聯
示例演示
后面學習設計模式,會繼續畫UML類圖
總結
搭建開發環境:npm init、webpack、babel
面向對象:概念、三要素、應用舉例、意義、是設計模式的基礎
UML類圖:類圖、關系、示例
工作中,每次新項目或者新功能開發之前,都建議先畫好 UML 圖,和同事一起確認評審。
總結
- 上一篇: 挑战赛额外战力什么意思
- 下一篇: (三)设计原则