前言:在此說明Javascript設(shè)計模式所講內(nèi)容和知識點(diǎn)來自雙越老師(wangEditor富文本開源作者)的視頻墨林,內(nèi)容通俗易懂宽菜,受益匪淺盼理,結(jié)合自己的學(xué)習(xí)心得整理成筆記,與大家分享智亮,愿在前端的道路上越走越遠(yuǎn).....
從“寫好代碼”到“設(shè)計代碼”的過程忆某,不僅是技術(shù)的提升,更是編程思維的提升鸽素,而這其中最關(guān)鍵的就是設(shè)計模式褒繁,是否理解并掌握設(shè)計模式,也是衡量程序員能力的標(biāo)準(zhǔn)之一馍忽。
學(xué)習(xí)前提
- 使用過jquery類庫
- 有ES6基礎(chǔ)棒坏,用過node.js和npm
- 對vue、react有所了解
搭建開發(fā)環(huán)境
代碼是基于ES6的遭笋,需要webpack和Babel進(jìn)行轉(zhuǎn)義
1坝冕、初始化npm環(huán)境
-
npm init 會出現(xiàn)提示,一直按回車瓦呼,最后輸入yes即可
image.png
2喂窟、安裝webpack(當(dāng)下流行的打包工具)
- 普通安裝:npm install webpack webpack-cli --save-dev
- 淘寶鏡像(http://npm.taobao.org/)安裝:npm install webpack webpack-cli --save-dev --registry=https://registry.npm.taobao.org
3、安裝webpack-dev-server(是webpack集成本地服務(wù)的一個環(huán)境央串,寫完代碼需要在本地預(yù)覽磨澡,修改文件后可以自動刷新)
- npm install webpack-dev-server html-webpack-plugin --save-dev
4、安裝babel(解析ES6語法)
- npm install babel-core babel-loader babel-polyfill babel-preset-es2015 babel-preset-latest babel-plugin-transform-decorators-legacy --save-dev
5质和、創(chuàng)建文件
-
文件目錄結(jié)構(gòu)
image.png 創(chuàng)建webpack.dev.config.js文件進(jìn)行配置
// 引入 node.js path文件
const path = require('path')
// require 網(wǎng)頁模板插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 入口文件
entry: './src/index.js',
/*
出口文件
@param __dirname 當(dāng)前目錄
@param filename 目錄文件名
*/
output: {
path: __dirname,
filename: './release/bundle.js' // release 文件夾運(yùn)行時會自動創(chuàng)建
},
/*
plugins插件列表稳摄,是一個數(shù)組
@param HtmlWebpackPlugin html模板
*/
plugins: [
new HtmlWebpackPlugin({
template: './index.html' // 自動生成的bundle.js 會自動注入到index.html
})
],
// 本地開發(fā)環(huán)境服務(wù)器
devServer: {
// 需要獲取文件,從本地release文件夾里面獲取
contentBase: path.join(__dirname, "./release"), // 根目錄
open: true, // 自動打開瀏覽器
port: 9000, // 端口
},
// 模塊
module: {
// 規(guī)定
rules: [{
// 檢驗(yàn)js文件
test: /\.js?$/,
// 忽略的文件
exclude: /(node_modules)/,
// 進(jìn)行babel處理
loader: 'babel-loader'
}]
}
}
- 創(chuàng)建.babelrc文件
{
"presets": ["es2015", "latest"],
"plugins": ["transform-decorators-legacy"]
}
- 更改package.json文件(json文件里面不能添加注釋)
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 運(yùn)行webpack命令,將配置指向webpack.dev.config.js文件,生成開發(fā)模式--mode development
"dev": "webpack-dev-server --config ./webpack.dev.config.js --mode development"
},
-
運(yùn)行npm run build,自動生成release文件
image.png -
運(yùn)行npm run dev,自動打開瀏覽器
image.png
面向?qū)ο?/h2>
概念
1饲宿、類厦酬,即模板胆描,通過模板實(shí)例化很多對象,和es5的構(gòu)造函數(shù)原理相同,里面放屬性和方法
//1仗阅、創(chuàng)建一個人(People)的模板
//2昌讲、人具有姓名(name),年齡(age)的屬性
//3减噪、人可以執(zhí)行動作吃飯(eat())短绸、講話(speak())等方法,方法里面執(zhí)行邏輯操作
//1旋廷、創(chuàng)建一個人(People)的模板
class People {
constructor(name, age) {
//2鸠按、人具有姓名(name),年齡(age)的屬性
this.name = name,
this.age = age
}
//3饶碘、人可以執(zhí)行動作吃飯(eat())、講話(speak())等方法馒吴,方法里面執(zhí)行邏輯操作
eat() {
console.log('this is eat')
}
speak() {
console.log(this.name, this.age)
}
}
2扎运、對象(實(shí)例),通過類可以賦值給很多對象
// 1饮戳、創(chuàng)建一個叫zhang的對象
// 2豪治、因?yàn)槿说腸onstructor里面需要傳參數(shù),所以將zhang的姓名(name)和年齡(age)傳進(jìn)去
// 3扯罐、zhang便有人(People)的方法负拟,可以吃(eat()),可以說(speak())
const zhang = new People('zhang', 20)
console.log(zhang.eat()) // zhangeat
console.log(zhang.speak()) // 20
// 創(chuàng)建實(shí)例2
const wang = new People('wang', 30)
console.log(wang.eat())
console.log(wang.speak())
三要素:繼承、封裝歹河、多態(tài)
1掩浙、繼承,子類繼承父類
- 父類
//1秸歧、創(chuàng)建一個人(People)的模板厨姚,相當(dāng)于父類
class People {
constructor(name, age) {
//2、人具有姓名(name)键菱,年齡(age)的屬性
this.name = name,
this.age = age
}
//3谬墙、人可以執(zhí)行動作吃飯(eat())、講話(speak())等方法经备,方法里面執(zhí)行邏輯操作
eat() {
console.log(`${this.name}eat`)
}
speak() {
console.log(`${this.age}`)
}
}
- 子類(學(xué)生)
// 實(shí)現(xiàn)子類繼承父類
// 人分為好多種拭抬,比如學(xué)生、白領(lǐng),通過extends繼承人的屬相和方法
class Student extends People {
constructor(name,age,schoolNum){
// 通過關(guān)鍵字super將name,age交給父類處理
super(name,age)
// 自己處理學(xué)號
this.schoolNum = schoolNum
}
// 因?yàn)槭菍W(xué)生侵蒙,具有學(xué)習(xí)的方法
study(){
console.log(`學(xué)號為${this.schoolNum}的學(xué)生學(xué)習(xí)`)
}
}
// 創(chuàng)建實(shí)例(學(xué)生jialin)
const jiaLin = new Student('jialin',20,20120102)
// jialin具有學(xué)習(xí)的方法造虎,同時也具有人(People)的吃飯(eat())方法和說話(speak())方法
console.log(jiaLin.study())
console.log(jiaLin.eat())
console.log(jiaLin.speak())
- 子類(白領(lǐng))
// 創(chuàng)建白領(lǐng)這個類,繼承人的屬性和方法
class whiteCollar extends People{
constructor(name,age,workNum){
// 通過關(guān)鍵字super將name,age交給父類構(gòu)造函數(shù)處理
super(name,age)
// 自己處理工號
this.workNum = workNum
}
// 因?yàn)槭前最I(lǐng),具有工作的方法
work(){
console.log(`工號號為${this.workNum}的人工作`)
}
}
// 創(chuàng)建實(shí)例(白領(lǐng)mumu)
const mumu = new whiteCollar('mumu',30,123)
// mumu具有工作的方法蘑志,同時也具有人(People)的吃飯(eat())方法和說話(speak())方法
console.log(mumu.work()) // 工號號為123的人工作
console.log(mumu.eat())
console.log(mumu.speak())
通過以上案列可以知道子類(學(xué)生累奈、白領(lǐng))不僅繼承(擁有)了父類(人People)的屬性和方法贬派,還有屬于自己的方法(學(xué)習(xí)study、工作work)澎媒,自己也可以定義屬性和方法
- 總結(jié)
1搞乏、People 是父類,公共的戒努,不僅僅服務(wù)于Student和whiteCollar
2请敦、繼承可將公共方法抽離出來,提高復(fù)用储玫,減少冗余侍筛,這是軟件設(shè)計最基礎(chǔ)和最高效的方式
2、封裝撒穷,數(shù)據(jù)的權(quán)限和保密匣椰。簡單來說,將對象里面的某些屬性和方法不想讓別人看見端礼,有一些是可以開放出去(javascript不是很明顯禽笑,typescript[是js的超集]具有明顯的特征,如public蛤奥、private佳镜、protexted關(guān)鍵字)
public 完全開放
protectted 受保護(hù)的
private 私有的
- 演示的為typescript語法,代碼可以在此運(yùn)行http://www.typescriptlang.org/play/index.html
class People {
// ts中的屬性要先聲明
name
// 默認(rèn)的是public 相當(dāng)于public age
age
// 定義protected 受保護(hù)的屬性凡桥,只有自己或者子類可以訪問
protected weigth
// 定義private 私有的屬性蟀伸,別人用不了
private girlFriend
constructor(name, age) {
this.name = name
this.age = age
// 給weigth賦值
this.weigth = 120
this.girlFriend = "zdy"
}
eat() {
console.log(`${this.name}eat`)
}
}
class Student extends People{
schoolNum
constructor(name,age,schoolNum) {
super(name, age)
this.schoolNum = schoolNum
}
getWeight() {
// 獲取weight,這個屬性來自父類,對子類是開放的
console.log(this.weigth)
// 這里獲取不到 girlFriend缅刽,是父類私有的啊掏,不對外開放
}
}
// 創(chuàng)建實(shí)例
let mumu = new Student('mumu',20,201210)
mumu.getWeight() //120
// console.log(mumu.girlFriend) 編譯是會報錯,因?yàn)間irFriend是私有屬性
- 總結(jié)
1拷恨、減少耦合脖律,不該外露的不外露
2、利于數(shù)據(jù)腕侄、接口的權(quán)限管理
3小泉、es6目前不支持,一般認(rèn)為_開頭的屬性是private冕杠,比如var _num = 20
3微姊、多態(tài),同一接口的不同實(shí)現(xiàn)分预,簡單來講就是父類定義一個接口兢交,子類實(shí)現(xiàn)不同的功能
- 代碼演示
class People{
constructor(name){
this.name = name
}
saySomething(){
}
}
// a繼承 People
class A extends People {
constructor(name){
super(name)
}
saySomething(){
alert(`${this.name}`)
}
}
// b繼承 People
class B extends People {
constructor(name){
super(name)
}
saySomething(){
alert(`${this.name}`)
}
}
// a、b使用父類People的saySomething()方法笼痹,展示不一樣的結(jié)果配喳,此為多態(tài)
let a = new A('jialin')
alert(a.saySomething())
let b = new A('mumu')
alert(b.saySomething())
- 總結(jié)
1酪穿、保持子類的開放性和靈活性
2、面向接口編程(不用管子類如何實(shí)現(xiàn)晴裹,就看父類有多少接口)
面向?qū)ο笤谇岸藢?shí)際應(yīng)用
1被济、可以理解jquery就是個class
2、$('p')是jquery的一個實(shí)例
- 代碼演示
class jQuery {
constructor(selector) {
// 獲取數(shù)組的slice
let slice = Array.prototype.slice
// 獲取節(jié)點(diǎn)涧团,利用slice.call將其結(jié)果返回給一個數(shù)組只磷,因?yàn)榭赡苁嵌鄠€dom節(jié)點(diǎn)
let dom = slice.call(document.querySelectorAll(selector))
// 獲取dom的長度
let len = dom ? dom.length : 0
// 進(jìn)行循環(huán)
for (let i = 0; i < len; i++) {
// 將dom的數(shù)組元素賦值給this也就是實(shí)例的元素,元素的k就是數(shù)組的k泌绣,0,1,2...
this[i] = dom[i]
}
// 賦值數(shù)組的長度
this.length = len
this.selector = selector || ''
}
append(node) {
//...
}
addClass(name) {
//...
}
html(data) {
//...
}
// 此處省略若干 API
}
// 入口
window.$ = function(selector) {
// 這里其實(shí)就是工廠模式
return new jQuery(selector)
}
console.log($('p'))
為什么使用面向?qū)ο?/h4>
1钮追、程序的執(zhí)行離不開順序、判斷阿迈、循環(huán)操作元媚,也就是將其結(jié)構(gòu)化
2、面向?qū)ο缶褪菍⒘闵⒌臄?shù)據(jù)結(jié)構(gòu)化
3苗沧、對于計算機(jī)而言惠毁,結(jié)構(gòu)化的才是最簡單的
4、編程應(yīng)該是 簡單&抽象崎页,簡單的前提是抽象,抽象后才簡單
關(guān)于抽象:抽取事物的共同特征就是抽取事物的本質(zhì)特征腰埂,舍棄非本質(zhì)的特征飒焦。所以抽象的過程也是一個裁剪的過程。在抽象時屿笼,同與不同牺荠,決定于從什么角度上來抽象。抽象的角度取決于分析問題的目的驴一。