前言:在此说明Javascript设计模式所讲内容和知识点来自双越老师(wangEditor富文本开源作者)的视频,内容通俗易懂,受益匪浅,结合自己的学习心得整理成笔记,与大家分享,愿在前端的道路上越走越远.....
从“写好代码”到“设计代码”的过程,不仅是技术的提升,更是编程思维的提升,而这其中最关键的就是设计模式,是否理解并掌握设计模式,也是衡量程序员能力的标准之一。
学习前提
使用过jquery类库
有ES6基础,用过node.js和npm
对vue、react有所了解
搭建开发环境
代码是基于ES6的,需要webpack和Babel进行转义
1、初始化npm环境
npm init 会出现提示,一直按回车,最后输入yes即可
image.png
2、安装webpack(当下流行的打包工具)
普通安装: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集成本地服务的一个环境,写完代码需要在本地预览,修改文件后可以自动刷新)
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、创建文件
文件目录结构
image.png
创建webpack.dev.config.js文件进行配置
// 引入 node.js path文件 const path = require('path')// require 网页模板插件const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { // 入口文件 entry: './src/index.js', /* 出口文件 @param __dirname 当前目录 @param filename 目录文件名 */ output: { path: __dirname, filename: './release/bundle.js' // release 文件夹运行时会自动创建 }, /* plugins插件列表,是一个数组 @param HtmlWebpackPlugin html模板 */ plugins: [ new HtmlWebpackPlugin({ template: './index.html' // 自动生成的bundle.js 会自动注入到index.html }) ], // 本地开发环境服务器 devServer: { // 需要获取文件,从本地release文件夹里面获取 contentBase: path.join(__dirname, "./release"), // 根目录 open: true, // 自动打开浏览器 port: 9000, // 端口 }, // 模块 module: { // 规定 rules: [{ // 检验js文件 test: /\.js?$/, // 忽略的文件 exclude: /(node_modules)/, // 进行babel处理 loader: 'babel-loader' }] } }
创建.babelrc文件
{ "presets": ["es2015", "latest"], "plugins": ["transform-decorators-legacy"] }
更改package.json文件(json文件里面不能添加注释)
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", // 运行webpack命令,将配置指向webpack.dev.config.js文件,生成开发模式--mode development "dev": "webpack-dev-server --config ./webpack.dev.config.js --mode development" },
运行npm run build,自动生成release文件
image.png
运行npm run dev,自动打开浏览器
image.png
面向对象
概念
1、类,即模板,通过模板实例化很多对象,和es5的构造函数原理相同,里面放属性和方法
//1、创建一个人(People)的模板//2、人具有姓名(name),年龄(age)的属性//3、人可以执行动作吃饭(eat())、讲话(speak())等方法,方法里面执行逻辑操作//1、创建一个人(People)的模板class People { constructor(name, age) { //2、人具有姓名(name),年龄(age)的属性 this.name = name, this.age = age } //3、人可以执行动作吃饭(eat())、讲话(speak())等方法,方法里面执行逻辑操作 eat() { console.log('this is eat') } speak() { console.log(this.name, this.age) } }
2、对象(实例),通过类可以赋值给很多对象
// 1、创建一个叫zhang的对象// 2、因为人的constructor里面需要传参数,所以将zhang的姓名(name)和年龄(age)传进去// 3、zhang便有人(People)的方法,可以吃(eat()),可以说(speak())const zhang = new People('zhang', 20)console.log(zhang.eat()) // zhangeatconsole.log(zhang.speak()) // 20// 创建实例2const wang = new People('wang', 30)console.log(wang.eat())console.log(wang.speak())
三要素:继承、封装、多态
1、继承,子类继承父类
父类
//1、创建一个人(People)的模板,相当于父类class People { constructor(name, age) { //2、人具有姓名(name),年龄(age)的属性 this.name = name, this.age = age } //3、人可以执行动作吃饭(eat())、讲话(speak())等方法,方法里面执行逻辑操作 eat() { console.log(`${this.name}eat`) } speak() { console.log(`${this.age}`) } }
子类(学生)
// 实现子类继承父类// 人分为好多种,比如学生、白领,通过extends继承人的属相和方法class Student extends People { constructor(name,age,schoolNum){ // 通过关键字super将name,age交给父类处理 super(name,age) // 自己处理学号 this.schoolNum = schoolNum } // 因为是学生,具有学习的方法 study(){ console.log(`学号为${this.schoolNum}的学生学习`) } }// 创建实例(学生jialin)const jiaLin = new Student('jialin',20,20120102)// jialin具有学习的方法,同时也具有人(People)的吃饭(eat())方法和说话(speak())方法console.log(jiaLin.study())console.log(jiaLin.eat())console.log(jiaLin.speak())
子类(白领)
// 创建白领这个类,继承人的属性和方法class whiteCollar extends People{ constructor(name,age,workNum){ // 通过关键字super将name,age交给父类构造函数处理 super(name,age) // 自己处理工号 this.workNum = workNum } // 因为是白领,具有工作的方法 work(){ console.log(`工号号为${this.workNum}的人工作`) } }// 创建实例(白领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())
通过以上案列可以知道子类(学生、白领)不仅继承(拥有)了父类(人People)的属性和方法,还有属于自己的方法(学习study、工作work),自己也可以定义属性和方法
总结
1、People 是父类,公共的,不仅仅服务于Student和whiteCollar
2、继承可将公共方法抽离出来,提高复用,减少冗余,这是软件设计最基础和最高效的方式
2、封装,数据的权限和保密。简单来说,将对象里面的某些属性和方法不想让别人看见,有一些是可以开放出去(javascript不是很明显,typescript[是js的超集]具有明显的特征,如public、private、protexted关键字)
public 完全开放
protectted 受保护的
private 私有的
演示的为typescript语法,代码可以在此运行http://www.typescriptlang.org/play/index.html
class People { // ts中的属性要先声明 name // 默认的是public 相当于public age age // 定义protected 受保护的属性,只有自己或者子类可以访问 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,是父类私有的,不对外开放 } }// 创建实例let mumu = new Student('mumu',20,201210) mumu.getWeight() //120// console.log(mumu.girlFriend) 编译是会报错,因为girFriend是私有属性
总结
1、减少耦合,不该外露的不外露
2、利于数据、接口的权限管理
3、es6目前不支持,一般认为_开头的属性是private,比如var _num = 20
3、多态,同一接口的不同实现,简单来讲就是父类定义一个接口,子类实现不同的功能
代码演示
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()方法,展示不一样的结果,此为多态 let a = new A('jialin') alert(a.saySomething()) let b = new A('mumu') alert(b.saySomething())
总结
1、保持子类的开放性和灵活性
2、面向接口编程(不用管子类如何实现,就看父类有多少接口)
面向对象在前端实际应用
1、可以理解jquery就是个class
2、$('p')是jquery的一个实例
代码演示
class jQuery { constructor(selector) { // 获取数组的slice let slice = Array.prototype.slice // 获取节点,利用slice.call将其结果返回给一个数组,因为可能是多个dom节点 let dom = slice.call(document.querySelectorAll(selector)) // 获取dom的长度 let len = dom ? dom.length : 0 // 进行循环 for (let i = 0; i < len; i++) { // 将dom的数组元素赋值给this也就是实例的元素,元素的k就是数组的k,0,1,2... this[i] = dom[i] } // 赋值数组的长度 this.length = len this.selector = selector || '' } append(node) { //... } addClass(name) { //... } html(data) { //... } // 此处省略若干 API}// 入口window.$ = function(selector) { // 这里其实就是工厂模式 return new jQuery(selector) }console.log($('p'))
为什么使用面向对象
1、程序的执行离不开顺序、判断、循环操作,也就是将其结构化
2、面向对象就是将零散的数据结构化
3、对于计算机而言,结构化的才是最简单的
4、编程应该是 简单&抽象,简单的前提是抽象,抽象后才简单
关于抽象:抽取事物的共同特征就是抽取事物的本质特征,舍弃非本质的特征。所以抽象的过程也是一个裁剪的过程。在抽象时,同与不同,决定于从什么角度上来抽象。抽象的角度取决于分析问题的目的。
作者:jia林
链接:https://www.jianshu.com/p/2728597e6337