Giter Club home page Giter Club logo

stellaf.github.io's Introduction

home heroImage actionText actionLink footer
true
/cute.gif
Bonjour
/interview

stellaf.github.io's People

Contributors

stellayangf avatar zhufenglesson avatar

Watchers

 avatar  avatar

stellaf.github.io's Issues

React 基础篇

介绍

react 是一个 JavaScript 库,可构建用户界面,专注于视图,实现组件化开发

库相关

  • react.js React 核心
  • react-dom.js 提供与 DOM 相关功能,render 核心插入 DOM 元素。

组件开发

  • 可重组
  • 可复用
  • 可维护

实践

搭建开发环境

npm i create-react-app -g
create-react-app react-learning
cd react-learning
yarn start

JSX

什么是 JSX ?

  • JS 和 HTML 混合语法
  • 聚合 组件结构数据样式 进行组件定义
  • 语法糖,通过 bebel.js 转译为 createElement 语法

什么是元素?

  • 构成 React 应用最小单位
  • 描述屏幕所见内容
  • 普通 JS 对象,确保浏览器中 DOM 数据和 React 元素一致

等价代码

<h1 className='title' style={{ color: 'pink' }}>hello</h1>
React.createElement('h1', {
  className: 'title',
  style: {
    color: 'pink',
  }
}, 'hello');

// 结果
{
  type: 'h1',
  props: {
    className: 'title',
    style: {
      color: 'pink',
    }
  },
  children: 'hello'
}

书写形式

  • 表达式 { 表达式逻辑 }
  • 属性 className
  • 对象 <ul>{ 数组元素 }</ul>
  • 更新元素渲染 immutable,元素创建后,无法改变内容或属性,更新界面唯一办法,创建新元素。
  • 只更新已变化的内容

组件

组件规则

  • 必须大写字母开头
  • 返回值只能有一个根元素
  • 使用必须定义或引用它

函数组件

接收 props 返回 React 元素

function Header(props) {
  return <h1>Hello, { props.name }</h1>;
}

类组件

class Header extends React.Component {
  render() {
    return <h1>Hello, { props.name }</h1>;
  }
}

复合组件 & 提取组件

  • 细分小组件
  • 抽象出可复用组件,如:Button, Avatart, Slider

Props

只读性

  • 类似纯函数,只做计算
  • 不可修改传入的 Props

类型检查

  • 配置特定 propTypes 属性
  • defaultProps 定义默认 props 值

commitizen tools


sidebar: auto

Cz 工具交集使用篇

功能:

  • 规范 Git 精准提交说明
  • 多人协作,后期协作Bug 处理有据可查
  • 可根据规范的提交说明快速生成日志
  • 方便开发者或用户追踪项目开发信息和功能特性

目录:

  • 介绍符合 Angular规范 的提交说明
  • 介绍 Cz (适配器、校验、日志) 使用方法

规范 Git 提交说明

  • 提供更多历史信息,方便快速浏览
  • 过滤某些 commit, 便于筛选代码 review
  • 追踪 commit 生成更新日志
  • 关联 issue

Git 提交说明结构

分三个部分: Header, Body, Footer

<Header> <Body> <Footer>

Header

Header 部分包括三个字段: type(必需)、scope(可选)和 subject(必需)。

<type>(<scope>): <subject>
type

type用于说明 commit 的提交性质。

描述
feat 新增一个功能
fix 修复一个 Bug
docs 文档变更
style 代码格式
refeactor 代码重构
perf 改善性能
test 测试
build 变更项目构建或外部依赖
ci 更改持续继承软件的配置和 package.json 中 scripts 命令
chore 变更构建流程或辅助工具
revert 代码回退
scope

scope 说明 commit 影响的范围。scope 依据项目而定,例如在业务项目中可以依据菜单或者功能模块划分,如果是组件库开发,则可以依据组件划分。

Tip: scope 可选

subject

subject 是 commit 的简短描述。

Body

commit 的详细描述,说明代码提交的详细说明。

Footer

如果代码的提交是不兼容变更关闭缺陷,则 Footer 必需,否则可以省略。

不兼容变更

当前代码与上一个版本不兼容,则 Footer 以 BREAKING CHANGE 开头,后面是对变动的描述、以及变动的理由和迁移方法。

关闭缺陷

如果当前提交是针对特定的 issue,那么可以在 Footer 部分填写需要关闭的单个 issue 或一系列issues。

Commitizen

  • commitizen/cz-cli 是一个可以实现规范的提交说明的工具
  • 提供选择的提交信息类别,快速生成提交说明。安装cz工具:
npm i commitizen -g

Commitizen 适配器

cz-conventional-changelog

如果需要在项目中使用 commitizen 生成符合 AngularJS 规范的提交说明,初始化cz-conventional-changelog 适配器:

slot default

commitizen init cz-conventional-changelog --save --save-exact

如果当前已经有其他适配器被使用,则会报以下错误,此时可以加上--force选项进行再次初始化

slot default

Error: A previous adapter is already configured. Use --force to override

初始化命令主要进行了3件事情:

  • 在项目中安装 cz-conventional-changelog 适配器依赖
  • 将适配器依赖保存到package.json的 devDependencies 字段信息
  • 在 package.json 中新增 config.commitizen 字段信息,主要用于配置cz工具的适配器路径:

slot default

"devDependencies": {
 "cz-conventional-changelog": "^2.1.0"
},
"config": {
  "commitizen": {
    "path": "./node_modules/cz-conventional-changelog"
  }
}

接下里 git cz 代替 git commit 进行提交说明。

cz-customizable

如果想定制项目的提交说明,可以使用 cz-customizable 适配器

安装 cz-customizable

slot default

npm i cz-customizable -D

更新 package.json 文件

将之前符合Angular规范的 cz-conventional-changelog 适配器路径改成 cz-customizable 适配器路径:

slot default

"devDependencies": {
  "cz-customizable": "^5.3.0"
},
"config": {
  "commitizen": {
    "path": "node_modules/cz-customizable"
  }
}

新建 .cz-config.js 文件

cz-customizable will first look for a file called .cz-config.js,alternatively add a config block in your package.json。

官方提供了一个 .cz-config.js 示例文件 cz-config-EXAMPLE.js,如下所示:

'use strict';

module.exports = {

  types: [
    {value: 'feat',     name: 'feat:     A new feature'},
    {value: 'fix',      name: 'fix:      A bug fix'},
    {value: 'docs',     name: 'docs:     Documentation only changes'},
    {value: 'style',    name: 'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)'},
    {value: 'refactor', name: 'refactor: A code change that neither fixes a bug nor adds a feature'},
    {value: 'perf',     name: 'perf:     A code change that improves performance'},
    {value: 'test',     name: 'test:     Adding missing tests'},
    {value: 'chore',    name: 'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation'},
    {value: 'revert',   name: 'revert:   Revert to a commit'},
    {value: 'WIP',      name: 'WIP:      Work in progress'}
  ],

  scopes: [
    {name: 'accounts'},
    {name: 'admin'},
    {name: 'exampleScope'},
    {name: 'changeMe'}
  ],

  // it needs to match the value for field type. Eg.: 'fix'
  /*
  scopeOverrides: {
    fix: [
      {name: 'merge'},
      {name: 'style'},
      {name: 'e2eTest'},
      {name: 'unitTest'}
    ]
  },
  */
  // override the messages, defaults are as follows
  messages: {
    type: 'Select the type of change that you\'re committing:',
    scope: '\nDenote the SCOPE of this change (optional):',
    // used if allowCustomScopes is true
    customScope: 'Denote the SCOPE of this change:',
    subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
    body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
    breaking: 'List any BREAKING CHANGES (optional):\n',
    footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
    confirmCommit: 'Are you sure you want to proceed with the commit above?'
  },

  allowCustomScopes: true,
  allowBreakingChanges: ['feat', 'fix'],

  // limit subject length
  subjectLimit: 100
  
};

Commitizen校验

commitlint

校验提交说明是否符合规范,安装校验工具 commitlint

npm install --save-dev @commitlint/cli

@commitlint/config-conventional

安装符合Angular风格的校验规则

npm install --save-dev @commitlint/config-conventional 

在项目中新建commitlint.config.js文件并设置校验规则:

module.exports = {
  extends: ['@commitlint/config-conventional'],
};

安装huksy(git钩子工具)

npm install husky --save-dev

在package.json中配置git commit提交时的校验钩子:

"husky": {
  "hooks": {
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }  
}

需要注意,使用该校验规则不能对.cz-config.js进行不符合Angular规范的定制处理,例如之前的汉化,此时需要将.cz-config.js的文件按照官方示例文件cz-config-EXAMPLE.js进行符合Angular风格的改动。

commitlint-config-cz

如果是使用cz-customizable适配器做了破坏Angular风格的提交说明配置,那么不能使用**@commitlint/config-conventional**规则进行提交说明校验,可以使用commitlint-config-cz对定制化提交说明进行校验。

安装校验规则:

npm install commitlint-config-cz --save-dev

然后加入commitlint校验规则配置:

module.exports = {
  extends: [
    'cz'
  ]
};

validate-commit-msg

除了使用commitlint校验工具,也可以使用 validate-commit-msg 校验工具对cz提交说明是否符合Angular规范进行校验。

Commitizen日志

如果使用了cz工具集,配套conventional-changelog可以快速生成开发日志:

npm install conventional-changelog -D

在pacage.json中加入生成日志命令:

"scripts": {
  "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md"
}

执行 npm run changelog 后可查看生产的日志 CHANGELOG.md。

总结

后续可实现插件机制,规范代码提交说明。

参考

Cz 工具集

validate-commit-msg

Bugs Records

工作中的 Bug 修复记录

跨域

  • jsonp
  • proxy
  • CORS

使用 expose-loader 暴露全局库 lodash,浏览器运行显示 global 未定义

报错信息:Uncaught ReferenceError: global is not defined

解决:去掉 module.noParse 匹配库

{
  module: {
    // 去掉下面这行代码即可解决
    // noParse: /lodash/
  }
}

jQuery 在 Vue 中操作 DOM

数据更新后,重复给元素添加点击事件,导致菜单按钮失效
追加事件之前,解绑之前的点击事件即可:

$(selector).unbind();

// ....

EventLoop

事件环理解

名词解释

task:宏任务,包括:点击事件,setTimeout,setInterval 、setImmediate 、I/O 、UI rendering,Run script(主代码块)
microtask:微任务,包括:promise,MutationObserver(cb).observer(tag, options),Object.observe,process.nextTick(Node)
JS stack:JS 执行栈,函数执行时往主执行栈中添加一个执行上下文,该执行上下文结束后,就会退出执行栈,释放内存。

执行顺序 - 浏览器

Tasks, microtasks, queues and schedules

  • 思考:下面这段代码,点击 div.inner 会怎么执行?

    <div class="outer">
      <div class="inner"></div>
    </div>
    var outer = document.querySelector('.outer');
    var inner = document.querySelector('.inner');
    
    new MutationObserver(function () {
      console.log('mutate');
    }).observe(outer, {
      attributes: true,
    });
    
    function onClick() {
      console.log('click');
    
      setTimeout(function () {
        console.log('timeout');
      }, 0);
    
      Promise.resolve().then(function () {
        console.log('promise');
      });
    
      outer.setAttribute('data-random', Math.random());
    }
    
    inner.addEventListener('click', onClick);
    outer.addEventListener('click', onClick);

    如图:

    结果:

    click
    promise
    mutate
    click
    promise
    mutate
    timeout
    timeout

    过程解析:

    • 宏任务队列: Dispatch click -> setTimeout callback -> setTimeout callback
    • 执行栈: onClick -> onClick 出栈 -> Promise callback (出栈)-> Mutation callback (出栈)-> onClick (出栈) -> Promise callback (出栈)-> Mutation callback (出栈,结束!)
    • 打印日志: click -> promise -> mutate -> click -> promise -> mutate -> timeout -> timeout
    • 微任务队列:Promise then -> Mutation observers -> Promise then -> Mutation observers

    重要提示:执行栈中第一次 onClick 出栈后,代表当前执行栈为空,在进入下一个执行上下文前,会依次执行当前微任务队列中所有任务(每调取下一个宏任务前,都会清空微任务)。

    微任务清空:依次把微任务队列中的任务放到执行栈(主栈)中执行,再出栈。

    提示:Dispatch click 事件冒泡到 div.outer,继续进入 onClick 执行上下文

  • 思考:同样的代码,替代点击,程序调用 inner.click() 会怎么执行?

    结果:

    click
    click
    promise
    mutate
    promise
    timeout
    timeout

    重要提示:程序中调用 inner.click(),会在 JS stack 中推入一个 script 执行上下文(栈顶)。导致第一个 onClick 执行上下文执行出栈后,执行主栈并不为空,执行栈处于 mid-execution,不能清空微任务。
    此时,推入第二个 onClick 执行上下文。

    提示:注意第一个 mutationObserver 未执行处于 pending 状态时,不会再次触发,因此值打印一个 mutate

    提示:微任务执行,介于宏任务执行后和 UI 渲染前。

Basic Knowledge

Review

ES6

Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set本身是一个构造函数,用来生成 Set 数据结构。

Set 实例的属性和方法

Set 结构的实例有以下属性。

  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。

Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。

  • Set.prototype.add(value):添加某个值,返回 Set 结构本身。
  • Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
  • Set.prototype.clear():清除所有成员,没有返回值。

WeakSet

  • WeakSet 的成员只能是对象,而不能是其他类型的值。
  • WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
  • WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。
const foos = new WeakSet()
class Foo {
  constructor() {
    foos.add(this)
  }
  method () {
    if (!foos.has(this)) {
      throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
    }
  }
}

上面代码保证了 Foo 的实例方法,只能在 Foo 的实例上调用。这里使用 WeakSet 的好处是,foos对实例的引用,不会被计入内存回收机制,所以删除实例的时候,不用考虑foos,也不会出现内存泄漏。

三个方法:

  • WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
  • WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
  • WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet

Map

Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

实例方法和属性

  • size 属性
  • Map.prototype.set(key, value)
  • Map.prototype.get(key)
  • Map.prototype.has(key)
  • Map.prototype.delete(key)
  • Map.prototype.clear()

作为构造函数,Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"

函数扩展

函数的 length 属性

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function (a, b = 1, c) {}).length // 1

作用域

  • 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。
  • 等到初始化结束,这个作用域就会消失。
  • 这种语法行为,在不设置参数默认值时,是不会出现的。
var x = 1;

function f(x, y = x) {
  console.log(y);
}

f(2) // 2
let x = 1;

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // 1
function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // ReferenceError: x is not defined
var x = 1;

function foo(x = x) {
  // ...
}

foo() // ReferenceError: x is not defined

上面代码中,参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错”x 未定义“。

尾调用

尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。

尾调用:

function f(x){
  return g(x);
}

非尾调用:

// 情况一
function f(x){
  let y = g(x);
  return y;
}

// 情况二
function f(x){
  return g(x) + 1;
}

// 情况三
function f(x){
  g(x); // 最后一步是 return undefined
}
尾调优化

“尾调用优化”(Tail call optimization),即只保留内层函数的调用帧。

存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。

function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f();

// 等同于
function f() {
  return g(3);
}
f();

// 等同于
g(3);
尾递归

递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
阶乘

function factorial(n) {
  if (n === 1) return 1;
  return n * factorial(n-1);
}

计算n的阶乘,最多需要保存 n 个调用记录,复杂度 O(n) 。
阶乘优化

function factorial(n, total=1) {
  if (n ===1 ) return total;
  return factorial(n-1, n * total);
}

复杂度 O(1)
斐波拉切

function Fibonacci(n) {
  if (n <= 1) return 1;
  return Fibonacci(n-1) + Fibonacci(n-2);
}

斐波拉切 优化

function Fibonacci(n, ac1 = 1, ac2 = 1) {
  if (n<=1) return ac2;
  return Fibonacci(n-1, ac2, ac1+ac2);
}

小程序

生命周期函数

  • onLoad
  • onShow
  • onReady
  • onHide
  • onShow
  • onUnload

去抖 节流

去抖

function debounce(fn, delay) {
  let timer= null;

  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn(...args);
    }, delay);
  }
}

节流

function throttle(fn, delay) {
  let flag = false;

  return (...args) => {
    if (!flag) return;
    flag = false;
    setInterval(() => {
      fn(...args);
      flag = true;
    }, delay);
  }
}

缓存

作用:

  • 减少冗余数据传输,节省带宽
  • 减少服务器负担,大大提高网站性能
  • 加快客户端加载网页速度

cookie & session

cookie

参考链接

res.cookie(name, value, [, options])

参数:

  • domain
  • path
  • httpOnly
  • maxAge: Number
  • expires: Date
  • secure:只通过 https 协议访问

注意:

  • 可能被客户端篡改,使用前验证合法性
  • 不要存储敏感数据,比如用户密码,账户余额
  • 使用 httpOnly 保证安全
  • 尽量减少 cookie 的体积
  • 设置正确的 domain 和 path,减少数据传输

document.cookie 可以获取 cookie

session

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.