前端 ARTS 打卡计划(四)。
ARTS 打卡计划
第三十一周(2020.11.02-2020.11.08)
-
Algorithm:
- 485. 最大连续 1 的个数
- 595. 大的国家
-
# 给定一个 salary 表,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。 UPDATE salary SET sex = CASE sex WHEN 'm' THEN 'f' ELSE 'm' END;
-
Review:
-
Tip:
-
- 浏览器可以识别不规则、不合法标签(元素);
- 自定义继承自
HTMLElement
的类,称为自定义元素的类; - 经过
window.customElements.define
API 使得不合法标签(自定义元素)与自定义元素的类关联,实现合法化; - 通过模板标签
<template>
简化类的定义过程并添加样式; - 通过自定义元素的
attachShadow()
方法开启 Shadow DOM(这部分 DOM 默认与外部 DOM 隔离,内部任何代码都无法影响外部),隐藏自定义元素的内部实现; - 添加事件监听、进行组件化封装等。
- Web Components 的好处:
- 可以通过 shadow DOM 创建子 DOM 树,不会被页面上的 CSS 样式和 javascript 脚本所影响。
- 便于复用/重用;
- 相比于 Vue、React、Angular 等的组件化,Web Components 是原生的、框架无关的。
-
Element.getBoundingClientRect()
:返回元素的大小及其相对于视口的位置。getBoundingClientRect 方法用来描述一个元素的具体位置,该位置的下面四个属性都是相对于视口左上角的位置而言的。对某一节点执行该方法,它的返回值是一个 DOMRect 类型的对象。这个对象表示一个矩形盒子,它含有:left、top、right 和 bottom 等只读属性。
-
数组 reduce 方法的相关实现
- reduce 的实现
Array.prototype.customReduce = Array.prototype.reduce || function (callback, initialValue) { // 简单异常处理 if (this === null) { throw new TypeError( 'Array.prototype.customReduce ' + 'called on null or undefined' ); } if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 核心实现 let result = typeof initialValue === 'undefined' ? this[0] : initialValue; var startIndex = typeof initialValue === 'undefined' ? 1 : 0; this.slice(startIndex).forEach(function (val, index) { result = callback(result, val, index + startIndex, this); }); return result; }; [1, 2, 3, 5, 8].customReduce((pre, cur) => pre + cur); // 19 [1, 2, 3, 5, 8].customReduce((pre, cur) => pre + cur, 3); // 22
这里使用了 forEach,不想使用 forEach 或因兼容性考虑,可参考我之前的一篇文章JavaScript 很简单?那你理解的 forEach 真的对吗? ,自己实现 forEach,替换掉相关代码。
- 按顺序运行 Promise
// runPromiseInSequence 方法将会被一个每一项都返回一个 Promise 的数组调用,并且依次执行数组中的每一个 Promise const runPromiseInSequence = (array, value) => array.reduce( (promiseChain, currentFunction) => promiseChain.then(currentFunction), Promise.resolve(value) );
- 函数式方法 pipe 的实现
// pipe(f, g, h) 是一个 curry 化函数,它返回一个新的函数,这个新的函数将会完成 (...args) => h(g(f(...args))) 的调用。即 pipe 方法返回的函数会接收一个参数,这个参数传递给 pipe 方法第一个参数,以供其调用。 const pipe = (...functions) => (input) => functions.reduce((acc, fn) => fn(acc), input);
- Koa only 模块实现(Lodash 的 Pick、omit 方法同理)
const only = function (obj, keys) { obj = obj || {}; if ('string' == typeof keys) keys = keys.split(/ +/); return keys.reduce(function (ret, key) { if (null == obj[key]) return ret; ret[key] = obj[key]; return ret; }, {}); }; const o = { a: 'a', b: 'b', c: 'c', }; only(o, ['a', 'b']); // {a: 'a', b: 'b'}
- 告别繁琐的环境变量设置:Windows 使用 cmd 命令行查看、修改、删除与添加环境变量
# 查看当前所有可用的环境变量 set # 查看某个环境变量:查看path变量的值 set path # 修改环境变量(注意:这里是覆盖) set 变量名=变量内容 # 设置为空 set 变量名= # 给变量追加内容(%变量名%;代表以前的值) set 变量名=%变量名%;变量内容 # 将C:\Go\bin\添加到path中 set path=%path%;C:\Go\bin\
-
-
Share:
第三十二周(2020.11.09-2020.11.15)
-
Algorithm:
-
Review:
-
Tip:
- AntD Table:对于长表格,需要滚动才能查看表头和滚动条,那么现在可以设置跟随页面固定表头和滚动条(4.6.0 版本开始支持)
- 关于表格内编辑,优化方法!
git revert commit
(比如:352edf0feac10d6eb2cb249d11d9d7bbc82c58ee)撤销指定的版本,撤销也会作为一次提交进行保存。git revert
是提交一个新的版本,将需要 revert 的版本的内容再反向修改回去,版本会递增,不影响之前提交的内容。git revert
可以反复修改和恢复。- 常用
git stash
命令:git stash save "save message"
:执行存储时,添加备注,方便查找,只有git stash
也可以,但查找时不方便识别;git stash list
:查看 stash 了哪些存储;git stash show
:显示做了哪些改动,默认 show 第一个存储,如果要显示其他存贮,后面加stash@{$num}
,比如第二个git stash show stash@{1}
;git stash show -p
:显示第一个存储的改动,如果想显示其他存储,命令:git stash show stash@{$num} -p
,比如第二个:git stash show stash@{1} -p
;git stash apply
:应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即stash@{0}
,如果要使用其他个,git stash apply stash@{$num}
, 比如第二个:git stash apply stash@{1}
;git stash pop
:恢复之前缓存的工作目录,将缓存堆栈中的对应 stash 删除,并将对应修改应用到当前的工作目录下,默认为第一个 stash,即stash@{0}
,如果要应用并删除其他 stash,命令:git stash pop stash@{$num}
,比如应用并删除第二个:git stash pop stash@{1}
;git stash drop stash@{$num}
:丢弃stash@{$num}
存储,从列表中删除这个存储;git stash clear
:删除所有缓存的 stash。
- commit 过的
git reset --hard
,还有救吗?git reflog
找到对应 commit 的 hash、git reset --hard xxxhash
、git cherry-pick latesthash
:git 时光穿梭机–女神的侧颜- git 命令 log 与 reflog 的比较
- github 总结(4)–关于 git reset –hard 这个命令的惨痛教训
- mac 突然连不上 Wi-Fi:排除密码、DNS 等情况外,可以考虑是不是外接设备的问题。因为将 USB2.0 的接收器连接在 USB3.0 端口附近的插槽就会导致无线接收器信号被干扰。解决办法参考:
- 第一种,拔掉你的外接 type-c 就可以了(不是电源线,是你扩展的 type-c 接口,用来连接硬盘或者手机时候用的);
- 第二种,尝试换 mac 另一边的 type-c 接口进行连接;
- 第三种,更换一个 5GHz 的路由器。
- 正则比较字符串类型数字的大小【正整数、首位不为 0】
const strBaseNumber = Number(386).toString(); const arrBaseNumber = strBaseNumber.split(''); const len = strBaseNumber.length; // 生成正则:数位更多或者从高位开始比,数值更大 let strRegExp = `\\d{${len + 1}}`; arrBaseNumber.map((item, index) => { // 这里'^'和'$'不是必须的 strRegExp += `|${strBaseNumber.substring(index, -1) || '^'}[${ +item + 1 }-9]\\d{${len - index - 1}}$`; }); // 丢给ES进行查询请用下面的strRegExp结果 //let strRegExp = `[0-9]{${len+1}}`; //arrBaseNumber.map((item, index) => { // strRegExp += `|${strBaseNumber.substring(index,-1) || ''}[${+item + 1}-9][0-9]{${len - index - 1}}` //}); //"filter": { // "regexp": { // "suppierContractAmount.keyword": "[0-9]{5}|[2-9][0-9]{3}|1[1-9][0-9]{2}|10[1-9][0-9]{1}|100[1-9]" // } // } const regExp = new RegExp(strRegExp); console.log(regExp, strRegExp); console.log(regExp.test(385), regExp.test(386), regExp.test(387)); // false false true // 注意,数组[]前面的分号不可省略,否则会出现语法错误 [ '12', '334', '556', '1122', '5546', '234', '388', '387', '1234', '386', '385', ].filter((item) => { // 小于等于这里取反或者自行修改正则 if (regExp.test(item)) { return true; } }); // ["556", "1122", "5546", "388", "387", "1234"]
- 浏览器也可以开车?
console.log(
`%c
%c FBI WARNING %c
%c Federal Law provides severe civil and criminal penalties for
the unauthorized reproduction,distribution, or exhibition of
copyrighted motion pictures (Title 17, United States Code,
Sections 501 and 508). The Federal Bureau of Investigation
investigates allegations of criminal copyright infringement
(Title 17, United States Code, Section 506).
`,
'background: #000; font-size: 18px; font-family: monospace',
'background: #f33; font-size: 18px; font-family: monospace; color: #eee; text-shadow:0 0 1px #fff',
'background: #000; font-size: 18px; font-family: monospace',
'background: #000; font-size: 18px; font-family: monospace; color: #ddd; text-shadow:0 0 2px #fff'
);
把 js 代码,转成漂亮的代码图片:
效果图:
-
Share:
- 小蝌蚪传记:让接口提速 60%的优化技巧(代理层对接口数据进行了一次过滤,减少了 http 传输时延;引入 redis,减少了不必要的溯源。)
- 记一次 GraphQL 真正的详细入门:原生、koa2、的实战分享会
- JavaScript 20 年
第三十三周(2020.11.16-2020.11.22)
-
Algorithm:
-
Review:
-
Tip:
- primordials is not defined 错误:这里使用的 node 版本为 12,更换为 11.15.0,如果当前已经安装了 nvm 工具,可直接更换。没有的话需要卸载当前版本,再重新安装,或者安装 nvm,通过 nvm 来安装;
- TS 忽略类型检查:
// @ts-ignore
; /\d([a-c]+)/.test('12c')
:使用RegExp.$1
即可取到捕获的分组内容c
;-
失焦事件与点击事件冲突,导致不能正常选择值或者触发点击事件逻辑
- 场景:
- 下拉框中 blur 与 click 冲突
- 输入框 blur 与下方可点击浮沉 click 冲突:输入值时下方出现浮层,输入框失去焦点时,浮层隐藏;点击浮层条目触发搜索
// 点击弹窗条目进行搜索 handleSearch = (activeSearch) => { console.log(activeSearch); this.setState({ visible: false }); } // 获得焦点,有值时展示弹窗 onFocus = () => { if (this.state.keyword) { this.setState({ visible: true }); } } // 输入且有值时展示弹窗 onChange = (e) => { this.setState({ keyword: e.target.value, visible: !!e.target.value }) } // 失去焦点隐藏弹窗 onBlur = () => { if (this.state.keyword) { this.setState({ visible: false }); } } render() { const { keyword, visible } = this.state; return ( <div> <Input allowClear addonBefore={<Icon type="user" />} placeholder="支持ID、名称、主邮箱、客户经理、专属账户、客户ID、GroupID搜索" style={ { width: 460 } } onFocus={this.onFocus} onChange={this.onChange} onBlur={this.onBlur} /> { // 展示弹窗(点击条目完成搜索) visible && keyword && <div className={styles.SearchSelect}> { showOptions.map(item => ( <div onClick={() => this.handleSearch(item)} className={styles.item} key={item.key} > <div> {item.label}:{keyword} </div> </div> )) } </div> } </div> ); }
解决:
// 方法一:给失焦事件设置延迟触发 onBlur = () => { if (this.state.keyword) { setTimeout(() => { this.setState({ visible: false }); }, 300); } }; // 方法二:使用onMouseDown替代onClick // mousedown事件:当鼠标指针移动到元素上方,并按下鼠标按键时,会发生mousedown事件。 // mouseup事件:当在元素上放松鼠标按钮时,会发生mouseup事件。 // 方法三:保持 onClick 不变,添加`onMouseDown={(e) => { e.preventDefault() }};`;
- 场景:
-
Share:
第三十四周(2020.11.23-2020.11.29)
-
Algorithm:
-
Review:
-
Tip:
- Es 的模糊查询,match,match_phrase、wildcard 的区别(详见Elasticsearch 实践与总结)
-
Share:
第三十五周(2020.11.30-2020.12.06)
-
Algorithm:
-
Review:
-
Tip:
- 只会用 AntD 上传组件?除了 FormData 和 Blob,你还会怎么上传文件?
// DOM <input type='file' id='file' onChange={(e) => this.uploadFile(e, record)} /> // js uploadFile(e, record) { const file = e.target.files[0]; const reader = new FileReader(); reader.onloadend = () => { this.setState({ InvoiceFile: { Name: file.name, Buffer: reader.result.replace(/data.*base64[,]/, '') } }) } reader.readAsDataURL(file); }
- 只会用 AntD 上传组件?除了 FormData 和 Blob,你还会怎么上传文件?
-
Share:
第三十六周(2020.12.07-2020.12.13)
-
Algorithm:
-
Review:
-
Tip:
-
lodash 的 get 方法
- 语法:
_.get(object, path, [defaultValue])
object (Object)
: 要检索的对象path (Array|string)
: 要获取的对象路径[defaultValue] (*)
:如果解析值是 undefined,这值会被返回
- 应用
let object = { a: [{ b: { c: 3 } }] }; _.get(object, 'a[0].b.c'); // 3 _.get(object, ['a', '0', 'b', 'c']); // 3 _.get(object, 'a.b.c', 'default'); // default // 项目应用 >> 获取路由信息 获取不到的话返回404 matchRouter = this.$get(this.$route, 'matched[0].path', '/404');
- 语法:
-
ValidationError: Invalid options object.
报错
/src/index.less Module build failed: ValidationError: Invalid options object. Less Loader has been initialized using an options object that does not match the API schema. - options has an unknown property 'modifyVars'. These properties are valid: object { lessOptions?, additionalData?, sourceMap?, webpackImporter? }
这个实际上是 Less Loader 的版本导致的兼容性问题,需要更换 Less Loader 的版本。 问题的解决:把 Less Loader 进行降级,通过
yarn remove less-loader
命令卸载 Less Loader ,通过yarn add less-loader@5.0.0
命令安装 less-loader@5.0.0 的版本,然后问题就可以解决了。 -
-
Share:
第三十七周(2020.12.14-2020.12.20)
-
Algorithm:
-
Review:
-
Tip:
- Chrome 任务管理器:
shift + Esc
或者地址栏右键任务管理器打开。任务管理器的右键菜单可设置展示的列,进行性能检测分析。 - Windows Media Player 音频播放器倍速播放:界面右键单击鼠标,选择“增强功能”,“播放速度设置”。
-
常见构建工具及对比(Webpack/Grunt/Gulp)。
// gulpfile.js const { src, dest, parallel } = require('gulp'); const pug = require('gulp-pug'); const less = require('gulp-less'); const minifyCSS = require('gulp-csso'); const concat = require('gulp-concat'); function html() { return src('client/templates/*.pug').pipe(pug()).pipe(dest('build/html')); } function css() { return src('client/templates/*.less') .pipe(less()) .pipe(minifyCSS()) .pipe(dest('build/css')); } function js() { return src('client/javascript/*.js', { sourcemaps: true }) .pipe(concat('app.min.js')) .pipe(dest('build/js', { sourcemaps: true })); } exports.js = js; exports.css = css; exports.html = html; exports.default = parallel(html, css, js);
- scp 命令:scp 是 SSH 提供的一个客户端程序,用来在两台主机之间加密传送文件(即复制文件)。scp 是 secure copy 的缩写,相当于 cp 命令 + SSH。它的底层是 SSH 协议,默认端口是 22,相当于先使用 ssh 命令登录远程主机,然后再执行拷贝操作。使用 scp 传输数据时,文件和密码都是加密的,不会泄漏敏感信息。
- scp 主要用于以下三种复制操作。
- 本地复制到远程。
- 远程复制到本地。
- 两个远程系统之间的复制。
- scp 主要用于以下三种复制操作。
- react 设置多个 className:
className={`${styles.commonSelectOption} ${noErrorMessage ? styles.noErrorMessage : ''}`}
- form 表单出错,不展示提示,只输入框变红:
.noErrorMessage { :global { .ant-form-explain { display: none; } } }
- Chrome 任务管理器:
-
Share:
第三十八周(2020.12.21-2020.12.27)
-
Algorithm:
-
Review:
-
Tip:
- 万能命令-影视 VIP
- JS 中的原型链其实也是一个链表,只不过不是跟着
next
来查找,而是跟着__proto__
来查找的。
-
Share:
第三十九周(2020.12.28-2021.01.03)
-
Algorithm:
-
Review:
-
Tip:
- Source Map 在生成的文件末尾加上了类似
//@ sourceMappingURL=script.closure.js.map
的注释,浏览器就会加载script.closure.js.map
文件,并自动计算代码的实际位置:- JavaScript Source Map 详解
- devtool:Source Map 的 12 种模式。
- vscode 里的 launch.json 是干什么用的
- JS 在线代码片段性能测试工具
- https://jsperf.com(目前已不可用)
- https://jsbench.me/
- Benchmark.js:A robust benchmarking library that supports high-resolution timers & returns statistically significant results. As seen on jsPerf.
- 网站访问量及排名查看-Alexa
-
JS 深度优先遍历和广度优先遍历
// 深度优先遍历 const dfs = (root) => { console.log(root.val); root.children.forEach(dfs); }; // 广度优先遍历 const bfs = (root) => { const queue = [root]; while (queue.length) { const cur = queue.shift(); console.log(cur.val); cur.children.forEach((child) => queue.push(child)); } }; // 先序遍历 const pre = (root) => { if (!root) { return; } console.log(root.val); pre(root.left); pre(root.right); }; // 中序遍历 const inorder = (root) => { if (!root) { return; } inorder(root.left); console.log(root.val); inorder(root.right); }; // 后序遍历 const pos = (root) => { if (!root) { return; } pos(root.left); pos(root.right); console.log(root.val); };
- ES6 模块的特点是静态解析,而 commonJS 模块的特点是动态解析的,因此,借助 ES6 模块的静态解析,tree-shaking 的实现才能成为可能。
-
CSS 选择器之兄弟选择器(~和+):虽然这两个选择器都表示兄弟选择器,但是‘+’选择器则表示某元素后相邻的兄弟元素,也就是紧挨着的,是单个的。而‘~’选择器则表示某元素后所有同级的指定元素,强调所有的。
<!-- 可以借助兄弟选择器` ~ `实现`Radio.Button`选中前面的,给后面的加上假选中的样式 -- > <!-- 数据按照展示维度选项聚合时,选中高维度,需要让低纬度也有选中的背景效果 -- > :global { .ant-radio-button-wrapper-checked ~ label { border-color: #1890ff; } }
- Source Map 在生成的文件末尾加上了类似
-
Share:
第四十周(2021.01.04-2021.01.10)
-
Algorithm:
-
Review:
-
Tip:
-
JS 模拟浏览器强刷:
useEffect(() => { const oaStorage = localStorage.getItem('UCloud_OA_SupplierInfoList'); const curTime = new Date().getTime(); // 没有缓存或者缓存已经超过8个小时 if (!oaStorage || (oaStorage && curTime - Number(oaStorage) > 28800000)) { localStorage.setItem('UCloud_OA_SupplierInfoList', curTime); window.location.href = window.location.href.split('?')[0] + `?time=${curTime}`; // location.search += (location.search ? '&time=' : '?time=') + new Date().getTime() } }, []);
- 别再找什么时差计算器了,看看你在地球上生活了多少天:
parseInt((new Date().getTime() - new Date('1949-10-01').getTime()) / 1000 / 60 / 60 / 24)
; - form-data、x-www-form-urlencoded、raw、binary 的区别
- multipart/form-data:可以上传文件或者键值对,最后都会转化为一条消息;
- x-www-form-urlencoded:只能上传键值对,而且键值对都是通过&间隔分开的;
- raw 可以上传任意格式的文本,文本不做任何修饰传到服务端。比如传一些 xml,或者 json 数据,或者 text 文本数据;
- 相当于 Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。
- 4 种主流的 API 架构风格对比
-
-
Share: