Giter Club home page Giter Club logo

blogs's Issues

学习一项新技能

每次带着问题去了解,并做相关笔记整理。

基本

  • 一句话概括是什么
  • 官方文档走一遍
  • 写一个demo试试
  • 多读别人的项目或源码,试着去理解。
  • 自己尝试写一个作品

进价

  • 读十个以上开源项目或作品
  • 写十个以上项目或作品
  • 理解其内部实现机制和原理。
  • 反哺开源社区,对其提供优质作品,优化流程等等

参考

移动端手势

什么是手势

为什么要做手势

如何构建手势库

实现手势的底层原理

原生触摸事件

  • touchstart
  • touchmove
  • touchcancel
  • touchend

原生事件的缺陷

移动端click会有2个问题:

  • 会有200~300ms的延迟
  • 延迟响应,会出现穿透,即点击会触发非当前层的点击事件。

移动浏览器为什么会有300ms的延迟呢

是因为双击缩放的功能,这个功能最早是由iphone为解决访问网站所设计(当时主流网站都是为大屏设计)

300ms延迟目前最好的解决方案

  • 使用fastclick库,大概10k左右,如果不介意引入库大小
  • 封装一个tap事件,用例代替click事件。

常见的事件和手势

  • tap
  • longtap
  • dbtap
  • move/drag
  • swipe(Right/Left/Up/Down)
  • pinch/zoom
  • rotate

应用场景

实现手势的开源类库

参考

plantuml 安装graphviz失败处理[mac]

查看 brew.git 当前源

$ cd "$(brew --repo)" && git remote -v
origin https://github.com/Homebrew/brew.git (fetch)
origin https://github.com/Homebrew/brew.git (push)

查看 homebrew-core.git 当前源

$ cd "$(brew --repo homebrew/core)" && git remote -v
origin https://github.com/Homebrew/homebrew-core.git (fetch)
origin https://github.com/Homebrew/homebrew-core.git (push)

修改 brew.git 为阿里源

$ git -C "$(brew --repo)" remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git

修改 homebrew-core.git 为阿里源

$ git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git

zsh 替换 brew bintray 镜像

$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
$ source ~/.zshrc

bash 替换 brew bintray 镜像

$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile
$ source ~/.bash_profile

刷新源

$ brew update

切换完毕后再次执行brew install Graphviz ,成功!

参考:

js正则表达式

正则表达式,主要使用场景是针对字符串进行替换,分词摘取等

正则表达式测试:https://c.runoob.com/front-end/854
正则表达式图形理解:https://regexper.com/

一些有用的表达式:

生成ast时,需要做分词处理,比如

  1. html属性名称

通常是用字母、下划线、冒号开头(vue的绑定属性用:开头,通常我们不会这么定义)的,然后包含字母数字下划线中划线冒号和点的

const attrKey = /[a-zA-Z_:][-a-zA-Z0-9_:.]*/
  1. html的属性的
    有以下几种写法:
    class="title"
    class='title'
    class=title
const attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)=("([^"]*)"|'([^']*)'|([^\s"'=<>`]+)/

h5录屏记录

web常用事件

wiki: https://developer.mozilla.org/zh-CN/docs/Web/Events

{selector: 'body > #u1 .active '}

遇到问题

采集到输入后才添加的className,导致自动化脚本找不到元素

点击输入框,触发点击事件,采集到数据: {selector: 'body > .input-wrap .active'}
在自动化跑脚本时,.active样式是点击后才加上的,所以自动化时找不到此元素。
答:className由于有可能动态变化,所以,className标识元素不安全,应该采用tag来表示。

:nth-child()在selenium和puppeteer里表现不一致问题

// puppeteer里与document.querySelectorAll表现一致
document.querySelectorAll('body:nth-child(2)')
===
document.querySelectorAll('body')

//selenium里表示找body集合里第2个元素,与jquery api 表现一致。

node服务-babel7 最佳实践[项目搭建]

亮点

  • 纯node服务层,代码层使用es6+语法
  • 不需要webpack, rollup这些打包工具
  • 使用express搭建web服务
  • 使用nedb作为数据缓存
  • 使用bulebird构建Promise指令
  • 使用axios访问外部服务
  • 使用module-alias提供alias机制
  • 状态码分类,提供友好提示
  • 接口参数合法校验使用async-validator
  • 一些工具库:lodash, moment
    // todo

参考

sketch源文件的另类打开方式

  • 复制一份,备份
  • 右键源文件,另存为zip格式
  • 双击打开,就能看到文件目录结构:
document.json
meta.json
pages
previews
user.json

typescript类型声明

约束参数的函数类型,返回参数函数的返回值

  • 提取参数类型: Parameters
  • 提取函数返回值类型: ReturnType
const fnIntercept = <F extends (...args: any[]) => any>(fn: F, intercept) => {
  return (...args: Parameters<F>): ReturnType<F> => {
    intercept(...args);
    return fn(...args);
  };
};

astexplorer库 源码分析(-)

背景

为什么想分析这个库呢,因为我最近有个项目,想学习如何实现一个AST解析。

而这个库呢,包含了很多AST库如何解析,是一个非常好的入手项目。

线上地址:https://astexplorer.net/
仓库地址:https://github.com/fkling/astexplorer

技术架构

  • react
  • saga
  • redux

项目结构

// todos

核心**

parser

  • parser.loadParser
  • parser.parse(realParser, code, parserSettings || parser.getDefaultOptions())
  • parser.getNodeName(value)
  • parser.nodeToRange(value)
  • parser.forEachProperty(value)
  • parser.locationProps.has(key)
  • parser.typeProps.has(key)
  • parser.settings

ast

//todos

layout

左右2列布局

场景: 常见于移动端表单布局

使用flex布局,核心是justify-content: space-between; 表示:

均匀排列每个元素,首个元素放置于起点,末尾元素放置于终点

.layout-2-columns{
  display: flex;
  justify-content: space-between;
}
<div class="layout-2-columns" >
  <div class="label">城市</div>
  <div class="wrapper">
    <select name="cars" id="cars">
      <option value="volvo">Volvo</option>
      <option value="saab">Saab</option>
      <option value="mercedes">Mercedes</option>
      <option value="audi">Audi</option>
    </select>
  </div>
</div>

参考

使用issue来管理开源项目

提交PR的格式

feat: 添加了分享功能
​
给每篇博文添加了分享功能
​
- 添加分享到微博功能
- 添加分享到微信功能
- 添加分享到朋友圈功能
​
Issue #1, #2
Closes #1

type用于说明 commit 的类别,可以使用如下类别:

  • feat:新功能(feature)
  • fix:修补bug
  • doc:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

参考

如何优雅地pull request

奇技淫巧系列

位运算

按位操作符将其操作数当作 32 位的比特序列(由 0 和 1 组成)操作,返回值依然是标准的 JavaScript 数值

位运算在某些场景下,如需要大量计算的情况下,可以提高性能,比如图片处理,虚拟dom等

  1. & (按位与)

对每对比特位执行与(AND)操作。只有 a 和 b 都是 1 时,a AND b 才是 1。

场景:适用于频繁条件判断时使用

if (flags & VNodeFlags.ELEMENT) {
  // VNode 是普通标签
  mountElement(/* ... */)
} else if (flags & VNodeFlags.COMPONENT) {
  // VNode 是组件
  mountComponent(/* ... */)
} else if (flags & VNodeFlags.TEXT) {
  // VNode 是纯文本
  mountText(/* ... */)
}

参考

mac安装软件[记录]

通过nvm来切换node的版本时,需要注意先把全局安装的模块给安装到新的node版本里。

查看全局安装模块

npm ls -g --depth=0

卸载全局模块

npm uninstall -g [module xx]

管理node

  • nvm: 管理node版本
  • nrm: 管理node 模块的镜像地址
  • yrm 管理yarn模块的镜像地址

使用nvm切换node版本

永久切换

需要重新打开命令行,已打开的不生效

nvm alias default <版本号>

临时切换版本

临时切换版本,只在当前终端内有效,新开终端无效。

nvm use <版本号>

本地全局包

@vue/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

flex:1与文本过长显示省略号

直接贴最终代码: 传送门

我们知道css实现文本过长,实现省略号:

.text {
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.w100{ width: 100px;}
<div class="text w100">这段css要生效,前提是长度固定(例如width:100px),使用百分比都不行</div>

这段css要生效,前提是长度固定(例如width:100px),使用百分比都不行。

当使用flex布局时,固定长度+可变长度(适配不同移动端设备),这时需要注意几个css属性就可以实现

html结构需要调整:

<div class="filed">
  <div class="filed--label">萨达多撒多</div>
   <div class="filed-text">
      <div class="filed-text--wrapper">当使用flex布局时,固定长度+可变长度(适配不同移动端设备),这时需要注意几个css属性就可以实现</div>
   </div>
</div>
.filed { display: flex;}
.filed--label {width: 100px;}
.filed-text {
  flex:1;
  overflow: hidden;
}
.filed-text--wrapper {
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   width: 100%;
}

动态获取routes(require.context)

代码

require.context(
  './', true, 
  /^\.\/(?!utils|transpilers)[^/]+\/(transformers\/([^/]+)\/)?(codeExample\.txt|[^/]+?\.js)$/
  );

require.context语法

require.context(directory, useSubdirectories = false, regExp = /^\.\//);

这段代码的意思:

  • 嵌套遍历当前目录下的所有子目录,忽略路径包含utils,transpilers的文件
  • codeExample.text只能存在一级子目录或者/xx/transformers/xxx/目录下
  • 所有符合上述条件的js文件

使用场景

  • 动态路由获取

正则表达式

/^\.\/(?!utils|transpilers)[^/]+\/(transformers\/([^/]+)\/)?(codeExample\.txt|[^/]+?\.js)$/

codepen

codepen

涉及到的正则语法

匹配'x'仅仅当'x'后面不跟着'y',这个叫做正向否定查找。

例如,/\d+(?!.)/匹配一个数字仅仅当这个数字后面没有跟小数点的时候。正则表达式/\d+(?!.)/.exec("3.141")匹配‘141’而不是‘3.141’

x(?!y)

参考

npm包开发[健壮/可迭代]

在开发npm包时,约定目录结构,有助于理解代码结构。

lib包用途

功能 说明 场景
纯node环境 符合commonjs规范,适合node环境使用 node server端,比如工具包,日志等
浏览器使用 使用script方式引入 组件库,client端使用
cli命令行工具 命令行使用,例如工具包/脚手架之类 命令行工具

lib 包技术架构

统一使用ts编码,好处:类型提示

  • ts: 源码编写
  • rollup: 打包工具
  • doc: 文档工具

目录约定

按目录约定:

功能 说明
src 源码目录
lib 打包输出的代码,也有dist目录,可以统一约定lib
es 符合es module规范的代码
umd 符合umd规范的代码,给浏览器的script 直接饮用
typings 类型定义

假设开发一个lib包: lib-a, 按照约定:

lib-a
  ├── umd
  |    └── index.js
  ├── es
  |    └── index.js
  ├── lib
  |    └── index.js
  ├── src -- 源码目录
  |    └── index.js
  ├── typings
  |    └── index.d.ts
  ├── .gitignore
  └── package.json
// package.json
{
  "main": "lib/index.js",
  "module": "es/index.js",
  "types": "typings/index.d.ts"
}

文档

  • READMD.md - 这个是作为你的库在 npm 网站上的主页。
  • CHANGELOG.md
  • LICENSE

单测

单元测试,

benchmark (基准测试)

基准,用于基准测试,就是一个性能的衡量基准。

发布管理

使用semantic-release 去自动管理发布
可参考https://blog.dteam.top/posts/2020-05/semantic-release.html

参考

技能树

记录前端实用性的开源库

github manage project

使用github的功能来管理项目的整个迭代。

issues语言问题

issue,一般都是用英文写,那如果项目都用issue来创建,英语不好,全靠翻译,这尼玛自己给自己添堵呢!效率呢?
推荐issues-translate-action) 做双语翻译,nice!

理解宏任务和微任务

event loop

以一个宏任务(script(整体代码))开始,内部执行task,执行完当前所有的微任务队列后,单个宏任务完毕,返回值。
可以简单理解为2层循环,外层为宏任务循环,内存为微任务循环。

event loop

  • 宏任务主要有:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。
  • 微任务主要有:Promise.then、 MutationObserver、 process.nextTick(Node.js 环境)。

特点:

  • 如果函数的return值未被console,可以忽略,因为表现不一致(如果返回值使用了,就正常输出),跟引擎有关,暂不做深入
  • micro-task 当前循环会执行完全部微任务

执行下看看,会输出啥

(function test() {
    setTimeout(function() { console.log(1) }, 0); //回调会被添加到macro-task队列
    new Promise(function(resolve) {
        console.log(2);
        for (var i = 0; i < 10000; i++) {
            i == 9999 && resolve();
        }
        console.log(3);
    }).then(function() { // then 1
        console.log(4);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(5);
            }, 0);
            console.log(6);
        }).then(function() { // then 2
            console.log(7); //回调会在resolve后,添加到micro-task队列
        });
    }).then(function() { // then 3
        console.log(10);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(11);
            }, 0);
            console.log(12);
        }).then(function() { // then 4
            console.log(13); //回调会在resolve后,添加到micro-task队列
        });
    })
    console.log(8);
    return 9;
})();
//控制台打印的结果如下:
//2
//3
//8
//4
//6
//10
//12
//9 (此次是chrome输出的,干扰项,请忽略,因为多个语句块,也只返回最后一个,所以没有任何意义~)
//1
//5
//7
//11
//13

分析:

从script开始(整体代码):

第一轮:

入栈:
task = [
2,
3,
8,
]

console:
2,3,8,

简化宏任务,实际是发起异步任务,异步任务执行完毕,再将cb存放到macro-task

macro-task = [
1,
]
micro-task = [
then 1
]

执行micro-task: then 1
入栈:
task = [4, 6]
console:
4,6
macro-task = [
setTimeout(1),
setTimeout(5)
]
micro-task = [
then 3
]

执行micro-task:then 3
入栈:
task = [10, 12]
macro-task = [
setTimeout(1),
setTimeout(5),
setTimeout(11)
]

setTimeout(1) 直接执行,没啥可说的
...
执行macro-task: setTimeout(5)
入栈:
task = [5]
micro-task = [then 2]

最终console:
2,3,8,4,6,10,12
1,
5,7
11,13

能理解下面的,基本没问题了

let a = (function test() {
    setTimeout(function() { console.log(1) }, 0); //回调会被添加到macro-task队列
    new Promise(function(resolve) {
        console.log(2);
        for (var i = 0; i < 10000; i++) {
            i == 9999 && resolve();
        }
        console.log(3);
    }).then(function() { // then 1
        console.log(4);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(5);
            }, 0);
            console.log(6);
        }).then(function() { // then 2
            console.log(7); //回调会在resolve后,添加到micro-task队列
        });
    }).then(function() { // then 3
        console.log(10);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(11);
            }, 0);
            console.log(12);
        }).then(function() { // then 4
            console.log(13); //回调会在resolve后,添加到micro-task队列
        });
    })
    console.log(8);
    return 9;
})();
console.log(a)
console.log(77);

let b = (function test2 () {
    setTimeout(function() { console.log(21) }, 0);
    new Promise(function(resolve) {
        console.log(22);
        for (var i = 0; i < 10000; i++) {
            i == 9999 && resolve();
        }
        console.log(23);
    }).then(function() { // then 1
        console.log(24);
        new Promise(function(resolve) {
            setTimeout(function() { //回调会被添加到macro-task队列
                resolve();
                console.log(25);
            }, 0);
            console.log(26);
        }).then(function() { // then 2
            console.log(27); //回调会在resolve后,添加到micro-task队列
        });
    })
    console.log(88);
    return 99;
})();

console.log(b)

//控制台打印的结果如下:
//2
//3
//8
//9
//77
//22
//23
//88
//99
//4
//6
//24
//26
//10
//12
//1
//21
//5
//7
//25
//27
//11
//13 

参考 https://zhuanlan.zhihu.com/p/30894022 (图)

项目创建(模板)

在使用lerna publish时,确保以下2点:

  • node源为https://registry.npmjs.org/
  • npm账号为登录状态,因为lerna在提交时会创建git钩子。如果报错了,目前没有很好的方案去回滚解决。
npm login
Username: xxxxx
Password:
Email: (this IS public) [email protected]
Logged in as xxxxx on https://registry.npmjs.org/.

登录成功后,再使用lerna publish发布版本。

vue2.x的学习

watch的使用

监听数据变化时使用,一般用于当数据变化,需要执行联动时操作。

  1. 监听属性作为函数使用,监听某个数据,数据名称作为key:
    这种使用方式,在第一次绑定时,不会立即触发。只有等到监听属性变化时,才会触发。
watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  1. 监听属性作为对象使用,有handler函数和2个参数immediate和deep属性可使用
  • immediate:true 表示立即执行
  1. deep属性
    当需要监听某个data的嵌套属性时,这个字段就派上作用了。
watch: {
  obj: {
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true,
    deep: true
  }
} 

不过,这样写,可能会有性能影响,如果obj对象嵌套多,会造成一定的内存开销,可以用字符串形式监听。

优化完:

watch: {
 'obj.a': {
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true,
  }
} 

参考

webpack 4.x 最小压缩代码

codepen

(function(modules) { // webpackBootstrap
  // The module cache
  var installedModules = {};
  // The require function
  function __webpack_require__(moduleId) {
    // Check if module is in cache
    if (installedModules[moduleId]) {
      /******/
      return installedModules[moduleId].exports;
    }
    // Create a new module (and put it into the cache)
    var module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}
    };
    // Execute the module function
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    // Flag the module as loaded
    module.l = true;
    // Return the exports of the module
    return module.exports;
  }
  // expose the modules object (__webpack_modules__)
  __webpack_require__.m = modules;
  // expose the module cache
  __webpack_require__.c = installedModules;
  // define getter function for harmony exports
  __webpack_require__.d = function(exports, name, getter) {
    if (!__webpack_require__.o(exports, name)) {
      Object.defineProperty(exports, name, {
        enumerable: true,
        get: getter
      });
    }
  };
  // define __esModule on exports
  __webpack_require__.r = function(exports) {
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
      Object.defineProperty(exports, Symbol.toStringTag, {
        value: 'Module'
      });
    }
    Object.defineProperty(exports, '__esModule', {
      value: true
    });
  };
  // create a fake namespace object
  /******/
  // mode & 1: value is a module id, require it
  /******/
  // mode & 2: merge all properties of value into the ns
  /******/
  // mode & 4: return value when already ns object
  /******/
  // mode & 8|1: behave like require
  __webpack_require__.t = function(value, mode) {
    if (mode & 1) value = __webpack_require__(value);
    if (mode & 8) return value;
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    var ns = Object.create(null);
    __webpack_require__.r(ns);
    Object.defineProperty(ns, 'default', {
      enumerable: true,
      value: value
    });
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key,
    function(key) {
      return value[key];
    }.bind(null, key));
    return ns;
  };
  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function(module) {
    var getter = module && module.__esModule ?
    function getDefault() {
      return module['default'];
    }:
    function getModuleExports() {
      return module;
    };
    __webpack_require__.d(getter, 'a', getter);
    return getter;
  };
  // Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function(object, property) {
    return Object.prototype.hasOwnProperty.call(object, property);
  };
  // __webpack_public_path__
  __webpack_require__.p = "/";

  // Load entry module and return exports
  return __webpack_require__(__webpack_require__.s = "wNqJ");
})
({
  "wNqJ":
  (function(module, exports) {

    var add = function add() {
      console.log('add');
    };

    add();
  })
});

参考:

typescript 备忘录

ts周边

ts语法

ts类型库

ts playground

ts type unit test

类型挑战

npm, yarn常用命令

说明

abc包为例:

安装

# 安装到dependencies
npm i --save abc
yarn add abc

# 安装到devDependencies
npm i --save-dev abc
yarn add -D abc

# 全局安装
npm i -g abc
yarn global add abc

查看

# 项目
npm list
yarn list

# 全局查看
npm list -g --depth=0
yarn global list

删除

# 项目
npm uninstall abc
yarn remove abc

# 全局
npm uninstall -g abc
yyarn global remove abc

更新

# 项目
npm update abc
yarn upgrade abc

# 全局
npm update -g abc
yarn global upgrade abc

如何有效阅读开源库源码

工具

codecrumbs

可视化代码结构,给代码之前增加关联,注释及按步骤播放

madge

madge
代码生成依赖关系图

带着目的去看源码

带着一个问题去看,最小原则,去掉干扰元素。

astexplorer parser的实现

astexplorer 是一个集成了很多AST的编译器。可以实时看输出的AST语法。

我对其如何实现兼容多个版本的parser感兴趣,记录下我的整理思路。

问题

有的设计的parser会拆分成多个独立的模块,可能需要异步加载多个parser模块,这个怎么处理呢?

答:使用parser.loadParser去加载多个异步模块。

JS 基础

判断类型 作用
String string
Number number
Boolean boolean
Null object
Undefined undefined
Symbol symbol
BigInt bigint
Function function
宿主对象 (由 JS 环境提供)
其他任何对象 object

基本类型 (7种)

  • string
  • number
  • boolean
  • null
  • undefined
  • symbol
  • bigint(不常用)

除了 null 和 undefined之外,所有基本类型都有其对应的包装对象

typeof

类型
String string
Number number
Boolean boolean
Null object
Undefined undefined
Symbol symbol
BigInt bigint
Function function
宿主对象 (由 JS 环境提供)
其他任何对象 object

Object.js(o1, o2)

判断两个值是否相同

参考

editor

概述

整理遇到的编辑器

目录

  • sunmao-ui: 一个可扩展的低代码ui框架

【面向对象】设计模式:7大基本原则(5大核心原则+2补充原则)

SOLID 原则

  • S: 单一职责原则(Single Responsibility Principle, SRP)
  • O: 开闭原则(Open Closed Principle,OCP)
  • L:里氏代换原则(Liskov Substitution Principle,LSP)
  • I: 接口隔离原则(Interface Segregation Principle,ISP)
  • D: 依赖倒转原则(Dependency Inversion Principle,DIP)

面向对象的设计模式有七大基本原则

  • 单一职责原则(Single Responsibility Principle, SRP)
  • 开闭原则(Open Closed Principle,OCP)
  • 里氏代换原则(Liskov Substitution Principle,LSP)
  • 接口隔离原则(Interface Segregation Principle,ISP)
  • 依赖倒转原则(Dependency Inversion Principle,DIP)
  • 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
  • 最少知识原则(Least Knowledge Principle,LKP)或者迪米特法则(Law of Demeter,LOD)
标记 设计模式原则名称 简单定义
SRP 单一职责原则 一个类只负责一个功能领域中的相应职责
OCP 开闭原则 对扩展开放,对修改关闭
LSP 里氏代换原则 所有引用基类的地方必须能透明地使用其子类的对象
ISP 接口隔离原则 类之间的依赖关系应该建立在最小的接口上
DIP 依赖倒转原则 依赖于抽象,不能依赖于具体实现
CARP 合成/聚合复用原则 尽量使用合成/聚合,而不是通过继承达到复用的目的
LOD 迪米特法则 一个软件实体应当尽可能少的与其他实体发生相互作用

参考:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.