stellayangf / stellaf.github.io Goto Github PK
View Code? Open in Web Editor NEWStella Personal Blog.
Home Page: https://stellayangf.github.io/stella/
Stella Personal Blog.
Home Page: https://stellayangf.github.io/stella/
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
过程解析:
重要提示:执行栈中第一次 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 渲染前。
jsonp
proxy
CORS
报错信息:Uncaught ReferenceError: global is not defined
解决:去掉 module.noParse 匹配库
{
module: {
// 去掉下面这行代码即可解决
// noParse: /lodash/
}
}
数据更新后,重复给元素添加点击事件,导致菜单按钮失效
追加事件之前,解绑之前的点击事件即可:
$(selector).unbind();
// ....
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
createElement
语法等价代码
<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>;
}
}
propTypes
属性defaultProps
定义默认 props 值功能:
目录:
分三个部分: Header, Body, Footer
<Header> <Body> <Footer>
Header 部分包括三个字段: type
(必需)、scope
(可选)和 subject
(必需)。
<type>(<scope>): <subject>
type用于说明 commit 的提交性质。
值 | 描述 |
---|---|
feat | 新增一个功能 |
fix | 修复一个 Bug |
docs | 文档变更 |
style | 代码格式 |
refeactor | 代码重构 |
perf | 改善性能 |
test | 测试 |
build | 变更项目构建或外部依赖 |
ci | 更改持续继承软件的配置和 package.json 中 scripts 命令 |
chore | 变更构建流程或辅助工具 |
revert | 代码回退 |
scope 说明 commit 影响的范围。scope 依据项目而定,例如在业务项目中可以依据菜单或者功能模块划分,如果是组件库开发,则可以依据组件划分。
Tip: scope 可选
subject 是 commit 的简短描述。
commit 的详细描述,说明代码提交的详细说明。
如果代码的提交是不兼容变更或关闭缺陷,则 Footer 必需,否则可以省略。
当前代码与上一个版本不兼容,则 Footer 以 BREAKING CHANGE 开头,后面是对变动的描述、以及变动的理由和迁移方法。
如果当前提交是针对特定的 issue,那么可以在 Footer 部分填写需要关闭的单个 issue 或一系列issues。
npm i commitizen -g
如果需要在项目中使用 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件事情:
slot default
"devDependencies": {
"cz-conventional-changelog": "^2.1.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
接下里 git cz
代替 git commit
进行提交说明。
如果想定制项目的提交说明,可以使用 cz-customizable 适配器
slot default
npm i cz-customizable -D
将之前符合Angular规范的 cz-conventional-changelog 适配器路径改成 cz-customizable 适配器路径:
slot default
"devDependencies": {
"cz-customizable": "^5.3.0"
},
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
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
};
校验提交说明是否符合规范,安装校验工具 commitlint:
npm install --save-dev @commitlint/cli
安装符合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风格的改动。
如果是使用cz-customizable适配器做了破坏Angular风格的提交说明配置,那么不能使用**@commitlint/config-conventional**规则进行提交说明校验,可以使用commitlint-config-cz对定制化提交说明进行校验。
安装校验规则:
npm install commitlint-config-cz --save-dev
然后加入commitlint校验规则配置:
module.exports = {
extends: [
'cz'
]
};
除了使用commitlint校验工具,也可以使用 validate-commit-msg 校验工具对cz提交说明是否符合Angular规范进行校验。
如果使用了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。
后续可实现插件机制,规范代码提交说明。
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构。
Set 结构的实例有以下属性。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
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,也不会出现内存泄漏。
三个方法:
Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
作为构造函数,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属性将失真。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function (a, b = 1, c) {}).length // 1
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);
}
去抖
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);
}
}
作用:
res.cookie(name, value, [, options])
参数:
注意:
document.cookie 可以获取 cookie
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.