为了账号安全,请及时绑定邮箱和手机立即绑定

web前端进阶之Javascript设计模式面向对象篇

标签:
JavaScript

前言:在此说明Javascript设计模式所讲内容和知识点来自双越老师(wangEditor富文本开源作者)的视频,内容通俗易懂,受益匪浅,结合自己的学习心得整理成笔记,与大家分享,愿在前端的道路上越走越远.....

从“写好代码”到“设计代码”的过程,不仅是技术的提升,更是编程思维的提升,而这其中最关键的就是设计模式,是否理解并掌握设计模式,也是衡量程序员能力的标准之一。

学习前提

  • 使用过jquery类库

  • 有ES6基础,用过node.js和npm

  • 对vue、react有所了解

搭建开发环境

代码是基于ES6的,需要webpack和Babel进行转义

1、初始化npm环境

  • npm init 会出现提示,一直按回车,最后输入yes即可


    webp

    image.png

2、安装webpack(当下流行的打包工具)

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、创建文件

  • 文件目录结构


    webp

    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文件


    webp

    image.png

  • 运行npm run dev,自动打开浏览器


    webp

    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           私有的

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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消