diff --git a/.dumi/layouts/index.tsx b/.dumi/layouts/index.tsx deleted file mode 100644 index 25e85be..0000000 --- a/.dumi/layouts/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -// .dumi/theme/layout.tsx(本地主题) 或 src/layout.tsx(主题包) -import React from 'react'; -import Layout from 'dumi-theme-default/es/layout'; - -export default ({ children, ...props }) => ( - - <> - - {children} - - -); diff --git a/.dumi/theme/layout.tsx b/.dumi/theme/layout.tsx deleted file mode 100644 index 11eec89..0000000 --- a/.dumi/theme/layout.tsx +++ /dev/null @@ -1,32 +0,0 @@ -// .dumi/theme/layout.tsx(本地主题) 或 src/layout.tsx(主题包) -import React, { useEffect } from 'react'; -import Layout from 'dumi-theme-default/es/layout'; - -export default ({ children, ...props }) => { - const { history } = props; - - useEffect(() => { - const header = document.querySelector('.__dumi-default-navbar') - const cont = document.querySelector('.__dumi-default-layout-content') - const lo = document.querySelector('.__dumi-default-layout') - - if (location.hash === '#/resume' && lo) { - - cont.style.position = 'relative' - cont.style.top = '-64px' - header.style.display = 'none' - } else { - cont.style.position = 'relative' - cont.style.top = '0' - header.style.display = 'flex' - } - },[location.hash]) - - return ( - - <> - {children} - - - ) -}; diff --git a/docs/fea/Q&A/index.md b/docs/fea/Q&A/index.md index 656c41a..b2b4445 100644 --- a/docs/fea/Q&A/index.md +++ b/docs/fea/Q&A/index.md @@ -5,6 +5,7 @@ nav: group: title: 💊 Q&A order: 100 + path: /qa --- # 💊 Q&A diff --git a/docs/fea/canvas/base.md b/docs/fea/canvas/base.md index 5b841c5..518b7a0 100644 --- a/docs/fea/canvas/base.md +++ b/docs/fea/canvas/base.md @@ -5,6 +5,7 @@ nav: group: title: 💊 canvas order: 2 + path: /canvas --- ## 基础入门 @@ -15,41 +16,41 @@ group: import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - /** - * 绘制矩形 - * fillRect(x, y, w, h) 填充矩形 - * strokeRect(x, y, w, h) 边框矩形 - * clearRect(x, y, w, h) 清除指定区域 - */ - function fillRect() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + /** + * 绘制矩形 + * fillRect(x, y, w, h) 填充矩形 + * strokeRect(x, y, w, h) 边框矩形 + * clearRect(x, y, w, h) 清除指定区域 + */ + function fillRect() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - // 实心矩形 - ctx.fillStyle = 'red' - ctx.fillRect(25, 25, 50, 50) + // 实心矩形 + ctx.fillStyle = 'red'; + ctx.fillRect(25, 25, 50, 50); - // 空心矩形 - ctx.lineWidth = 1 - ctx.fillStyle = 'black' - ctx.strokeRect(75, 75, 50, 50) + // 空心矩形 + ctx.lineWidth = 1; + ctx.fillStyle = 'black'; + ctx.strokeRect(75, 75, 50, 50); - // 清除区域 - ctx.clearRect(50, 50, 50, 50) - } + // 清除区域 + ctx.clearRect(50, 50, 50, 50); + } - useEffect(() => { - fillRect() - }, []) + useEffect(() => { + fillRect(); + }, []); - return ( -
- -
- ) -} + return ( +
+ +
+ ); +}; ``` ### 三角形 @@ -58,40 +59,40 @@ export default () => { import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - /** - * 绘制三角形 - */ - function tri() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + /** + * 绘制三角形 + */ + function tri() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - // 实心三角形 - ctx.beginPath() - ctx.moveTo(90, 25) - ctx.lineTo(25, 90) - ctx.lineTo(155, 90) - ctx.fill() + // 实心三角形 + ctx.beginPath(); + ctx.moveTo(90, 25); + ctx.lineTo(25, 90); + ctx.lineTo(155, 90); + ctx.fill(); - ctx.beginPath() - ctx.moveTo(90, 155) - ctx.lineTo(25, 90) - ctx.lineTo(155, 90) - ctx.closePath() - ctx.stroke() - } + ctx.beginPath(); + ctx.moveTo(90, 155); + ctx.lineTo(25, 90); + ctx.lineTo(155, 90); + ctx.closePath(); + ctx.stroke(); + } - useEffect(() => { - tri() - }, []) + useEffect(() => { + tri(); + }, []); - return ( -
- -
- ) -} + return ( +
+ +
+ ); +}; ``` ### 绘制圆弧 @@ -100,38 +101,38 @@ export default () => { import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - // 绘制圆弧 - function drawArc() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + // 绘制圆弧 + function drawArc() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - let x = 90, - y = 90, - r = 30, - startAngle = 0, - endAngle = (Math.PI / 180) * 180 + let x = 90, + y = 90, + r = 30, + startAngle = 0, + endAngle = (Math.PI / 180) * 180; - ctx.beginPath() - ctx.arc(x, y, r, startAngle, endAngle, false) - ctx.fill() + ctx.beginPath(); + ctx.arc(x, y, r, startAngle, endAngle, false); + ctx.fill(); - ctx.beginPath() - ctx.arc(x, y, r, startAngle, endAngle, true) - ctx.stroke() - } + ctx.beginPath(); + ctx.arc(x, y, r, startAngle, endAngle, true); + ctx.stroke(); + } - useEffect(() => { - drawArc() - }, []) + useEffect(() => { + drawArc(); + }, []); - return ( -
- -
- ) -} + return ( +
+ +
+ ); +}; ``` ### 绘制贝塞尔曲线 @@ -140,44 +141,43 @@ export default () => { import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - /** - * quadraticCurveTo(cp1x, cp1y, x, y) cp1 为控制点 - * bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) cp1、cp2 为控制点 - * x、y 为结束点 - */ - function bezier() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + /** + * quadraticCurveTo(cp1x, cp1y, x, y) cp1 为控制点 + * bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) cp1、cp2 为控制点 + * x、y 为结束点 + */ + function bezier() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - // 二次贝塞尔曲线 - ctx.beginPath() - ctx.moveTo(30, 90) - ctx.quadraticCurveTo(15, 15, 90, 30) - ctx.quadraticCurveTo(165, 15, 150, 90) - ctx.quadraticCurveTo(148, 130, 70, 120) - ctx.quadraticCurveTo(65, 140, 40, 140) - ctx.quadraticCurveTo(65, 135, 55, 120) - ctx.quadraticCurveTo(30, 115, 30, 90) - ctx.stroke() + // 二次贝塞尔曲线 + ctx.beginPath(); + ctx.moveTo(30, 90); + ctx.quadraticCurveTo(15, 15, 90, 30); + ctx.quadraticCurveTo(165, 15, 150, 90); + ctx.quadraticCurveTo(148, 130, 70, 120); + ctx.quadraticCurveTo(65, 140, 40, 140); + ctx.quadraticCurveTo(65, 135, 55, 120); + ctx.quadraticCurveTo(30, 115, 30, 90); + ctx.stroke(); - ctx.font = '18px bold 黑体' - ctx.fillStyle = 'black' - ctx.fillText('聊天框', 120, 160) + ctx.font = '18px bold 黑体'; + ctx.fillStyle = 'black'; + ctx.fillText('聊天框', 120, 160); + } - } + useEffect(() => { + bezier(); + }, []); - useEffect(() => { - bezier() - }, []) - - return ( -
- -
- ) -} + return ( +
+ +
+ ); +}; ``` ### 绘制三次贝塞尔曲线 @@ -186,43 +186,43 @@ export default () => { import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - /** - * 绘制三次贝塞尔曲线 - * - */ - function beziers() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + /** + * 绘制三次贝塞尔曲线 + * + */ + function beziers() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - // 三次贝塞尔曲线 - ctx.beginPath() - ctx.moveTo(90, 40) - ctx.bezierCurveTo(90, 36, 70, 25, 50, 25) - ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5) - ctx.bezierCurveTo(20, 80, 40, 120, 90, 140) - ctx.bezierCurveTo(110, 135, 155, 110, 160, 62.5) - ctx.bezierCurveTo(160, 22, 140, 25, 130, 25) - ctx.bezierCurveTo(120, 25, 110, 30, 90, 40) - ctx.fillStyle = 'red' - ctx.fill() + // 三次贝塞尔曲线 + ctx.beginPath(); + ctx.moveTo(90, 40); + ctx.bezierCurveTo(90, 36, 70, 25, 50, 25); + ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5); + ctx.bezierCurveTo(20, 80, 40, 120, 90, 140); + ctx.bezierCurveTo(110, 135, 155, 110, 160, 62.5); + ctx.bezierCurveTo(160, 22, 140, 25, 130, 25); + ctx.bezierCurveTo(120, 25, 110, 30, 90, 40); + ctx.fillStyle = 'red'; + ctx.fill(); - ctx.font = '18px bold 黑体' - ctx.fillStyle = 'black' - ctx.fillText('爱心', 120, 160) - } + ctx.font = '18px bold 黑体'; + ctx.fillStyle = 'black'; + ctx.fillText('爱心', 120, 160); + } - useEffect(() => { - beziers() - }, []) + useEffect(() => { + beziers(); + }, []); - return ( -
- -
- ) -} + return ( +
+ +
+ ); +}; ``` ### 绘制笑脸 @@ -231,42 +231,41 @@ export default () => { import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - /** - * 绘制笑脸 - * - */ - function fillSmile() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + /** + * 绘制笑脸 + * + */ + function fillSmile() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - ctx.beginPath() - ctx.arc(75, 75, 50, 0, Math.PI * 2, true) - ctx.moveTo(110, 75) - ctx.arc(75, 75, 35, 0, Math.PI, false) - ctx.moveTo(65, 65) - ctx.arc(60, 65, 5, 0, Math.PI * 2, true) - ctx.moveTo(95, 65) - ctx.arc(90, 65, 5, 0, Math.PI * 2, true) - ctx.stroke() + ctx.beginPath(); + ctx.arc(75, 75, 50, 0, Math.PI * 2, true); + ctx.moveTo(110, 75); + ctx.arc(75, 75, 35, 0, Math.PI, false); + ctx.moveTo(65, 65); + ctx.arc(60, 65, 5, 0, Math.PI * 2, true); + ctx.moveTo(95, 65); + ctx.arc(90, 65, 5, 0, Math.PI * 2, true); + ctx.stroke(); - ctx.font = '18px bold 黑体' - ctx.fillStyle = 'black' - ctx.fillText('笑脸', 120, 160) - } + ctx.font = '18px bold 黑体'; + ctx.fillStyle = 'black'; + ctx.fillText('笑脸', 120, 160); + } + useEffect(() => { + fillSmile(); + }, []); - useEffect(() => { - fillSmile() - }, []) - - return ( -
- -
- ) -} + return ( +
+ +
+ ); +}; ``` ### 吃豆人 @@ -275,142 +274,137 @@ export default () => { import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() + const canvasRef = useRef(); - /** - * 吃豆人 - * - */ - function bean() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + /** + * 吃豆人 + * + */ + function bean() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - // 外墙 - _roundedRect(ctx, 12, 12, 160, 160, 15) - _roundedRect(ctx, 18, 18, 148, 148, 9) - // 内墙 - _roundedRect(ctx, 45, 50, 45, 30, 6) - _roundedRect(ctx, 115, 50, 45, 30, 6) - _roundedRect(ctx, 115, 110, 45, 50, 6) - _roundedRect(ctx, 45, 110, 45, 25, 6) + // 外墙 + _roundedRect(ctx, 12, 12, 160, 160, 15); + _roundedRect(ctx, 18, 18, 148, 148, 9); + // 内墙 + _roundedRect(ctx, 45, 50, 45, 30, 6); + _roundedRect(ctx, 115, 50, 45, 30, 6); + _roundedRect(ctx, 115, 110, 45, 50, 6); + _roundedRect(ctx, 45, 110, 45, 25, 6); - // 绘制吃豆人 - ctx.beginPath() - ctx.arc(35, 35, 10, Math.PI / 7, -Math.PI / 7, false) - ctx.lineTo(31, 37) - ctx.fill() + // 绘制吃豆人 + ctx.beginPath(); + ctx.arc(35, 35, 10, Math.PI / 7, -Math.PI / 7, false); + ctx.lineTo(31, 37); + ctx.fill(); - // 绘制魔鬼 - ctx.beginPath() - ctx.moveTo(83, 116) - ctx.lineTo(83, 102) - ctx.bezierCurveTo(83, 94, 89, 88, 97, 88) - ctx.bezierCurveTo(105, 88, 111, 94, 111, 102) - ctx.lineTo(111, 116) - ctx.lineTo(106.3, 111.3) - ctx.lineTo(97.3, 111) - ctx.lineTo(92, 116) - ctx.lineTo(87, 111) - ctx.lineTo(83, 116) - ctx.fill() + // 绘制魔鬼 + ctx.beginPath(); + ctx.moveTo(83, 116); + ctx.lineTo(83, 102); + ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); + ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); + ctx.lineTo(111, 116); + ctx.lineTo(106.3, 111.3); + ctx.lineTo(97.3, 111); + ctx.lineTo(92, 116); + ctx.lineTo(87, 111); + ctx.lineTo(83, 116); + ctx.fill(); - // 绘制小点 - for (let i = 0; i < 7; i++) { - ctx.fillRect(52 + i * 16, 35, 4, 4) - } - - // 绘制小点 - for (let i = 0; i < 7; i++) { - ctx.fillRect(28, 52 + i * 16, 4, 4) - } - - // 绘制小点 - for (let i = 0; i < 7; i++) { - ctx.fillRect(100, 52 + i * 16, 4, 4) - } - - // 绘制小点 - for (let i = 0; i < 8; i++) { - ctx.fillRect(44 + i * 16, 92, 4, 4) - } - - // 绘制小点 - for (let i = 0; i < 3; i++) { - ctx.fillRect(44 + i * 16, 148, 4, 4) - } - - ctx.fillStyle = 'white' - ctx.beginPath() - ctx.moveTo(91, 96) - ctx.bezierCurveTo(88, 96, 87, 99, 87, 101) - ctx.bezierCurveTo(87, 103, 88, 106, 91, 106) - ctx.bezierCurveTo(94, 106, 95, 103, 95, 101) - ctx.bezierCurveTo(95, 99, 94, 96, 91, 96) - ctx.moveTo(103, 96) - ctx.bezierCurveTo(100, 96, 99, 99, 99, 101) - ctx.bezierCurveTo(99, 103, 100, 106, 103, 106) - ctx.bezierCurveTo(106, 106, 107, 103, 107, 101) - ctx.bezierCurveTo(107, 99, 106, 96, 103, 96) - ctx.fill() - - // 右眼 - ctx.fillStyle = 'blue' - ctx.beginPath() - ctx.arc(101, 102, 2, 0, Math.PI * 2, true) - ctx.fill() - // 左眼 - ctx.beginPath() - ctx.arc(89, 102, 2, 0, Math.PI * 2, true) - ctx.fill() - - ctx.font = '18px bold 黑体' - ctx.fillStyle = 'black' - ctx.fillText('吃豆人', 180, 180) - - ctx.clearRect(150, 0, 100, 200) - - /** - * 绘制圆角矩形的函数 - * - * @param {*} ctx 画笔 - * @param {*} x x 坐标 - * @param {*} y y 坐标 - * @param {*} w 宽 - * @param {*} h 高 - * @param {*} r 半径 - */ - function _roundedRect(ctx, x, y, w, h, radius) { - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y + h - radius); - ctx.quadraticCurveTo(x, y + h, x + radius, y + h); - ctx.lineTo(x + w - radius, y + h); - ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - radius); - ctx.lineTo(x + w, y + radius); - ctx.quadraticCurveTo(x + w, y, x + w - radius, y); - ctx.lineTo(x + radius, y); - ctx.quadraticCurveTo(x, y, x, y + radius); - ctx.stroke(); - } + // 绘制小点 + for (let i = 0; i < 7; i++) { + ctx.fillRect(52 + i * 16, 35, 4, 4); } + // 绘制小点 + for (let i = 0; i < 7; i++) { + ctx.fillRect(28, 52 + i * 16, 4, 4); + } - useEffect(() => { - bean() - }, []) + // 绘制小点 + for (let i = 0; i < 7; i++) { + ctx.fillRect(100, 52 + i * 16, 4, 4); + } - return ( -
- -
- ) -} + // 绘制小点 + for (let i = 0; i < 8; i++) { + ctx.fillRect(44 + i * 16, 92, 4, 4); + } + + // 绘制小点 + for (let i = 0; i < 3; i++) { + ctx.fillRect(44 + i * 16, 148, 4, 4); + } + + ctx.fillStyle = 'white'; + ctx.beginPath(); + ctx.moveTo(91, 96); + ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); + ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); + ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); + ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); + ctx.moveTo(103, 96); + ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); + ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); + ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); + ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); + ctx.fill(); + + // 右眼 + ctx.fillStyle = 'blue'; + ctx.beginPath(); + ctx.arc(101, 102, 2, 0, Math.PI * 2, true); + ctx.fill(); + // 左眼 + ctx.beginPath(); + ctx.arc(89, 102, 2, 0, Math.PI * 2, true); + ctx.fill(); + + ctx.font = '18px bold 黑体'; + ctx.fillStyle = 'black'; + ctx.fillText('吃豆人', 180, 180); + + ctx.clearRect(150, 0, 100, 200); + + /** + * 绘制圆角矩形的函数 + * + * @param {*} ctx 画笔 + * @param {*} x x 坐标 + * @param {*} y y 坐标 + * @param {*} w 宽 + * @param {*} h 高 + * @param {*} r 半径 + */ + function _roundedRect(ctx, x, y, w, h, radius) { + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y + h - radius); + ctx.quadraticCurveTo(x, y + h, x + radius, y + h); + ctx.lineTo(x + w - radius, y + h); + ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - radius); + ctx.lineTo(x + w, y + radius); + ctx.quadraticCurveTo(x + w, y, x + w - radius, y); + ctx.lineTo(x + radius, y); + ctx.quadraticCurveTo(x, y, x, y + radius); + ctx.stroke(); + } + } + + useEffect(() => { + bean(); + }, []); + + return ( +
+ +
+ ); +}; ``` ```js - - - ``` - diff --git a/docs/fea/canvas/color.md b/docs/fea/canvas/color.md index 67a0052..69553a0 100644 --- a/docs/fea/canvas/color.md +++ b/docs/fea/canvas/color.md @@ -5,6 +5,7 @@ nav: group: title: 💊 canvas order: 2 + path: /canvas --- ## 颜色 @@ -13,286 +14,290 @@ group: import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() - const canvasRef2 = useRef() - const canvasRef3 = useRef() - const canvasRef4 = useRef() - const canvasRef5 = useRef() - const canvasRef6 = useRef() - const canvasRef7 = useRef() - const canvasRef8 = useRef() - const canvasRef9 = useRef() - const canvasRef10 = useRef() - const canvasRef11 = useRef() - const canvasRef12 = useRef() + const canvasRef = useRef(); + const canvasRef2 = useRef(); + const canvasRef3 = useRef(); + const canvasRef4 = useRef(); + const canvasRef5 = useRef(); + const canvasRef6 = useRef(); + const canvasRef7 = useRef(); + const canvasRef8 = useRef(); + const canvasRef9 = useRef(); + const canvasRef10 = useRef(); + const canvasRef11 = useRef(); + const canvasRef12 = useRef(); - function demo1() { - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + function demo1() { + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - for (let i = 0; i < 6; i++) { - for (let j = 0; j < 6; j++) { - ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(255 - 42.5 * j)}, 0)` - ctx.fillRect(j * 25, i * 25, 25, 25) - } - } + for (let i = 0; i < 6; i++) { + for (let j = 0; j < 6; j++) { + ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor( + 255 - 42.5 * j, + )}, 0)`; + ctx.fillRect(j * 25, i * 25, 25, 25); + } + } + } + + function demo2() { + let canvas = canvasRef2.current; + let ctx = canvas.getContext('2d'); + + for (let i = 0; i < 6; i++) { + for (let j = 0; j < 6; j++) { + ctx.strokeStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor( + 255 - 42.5 * j, + )}, 0)`; + ctx.beginPath(); + ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true); + ctx.stroke(); + } + } + } + + function demo3() { + let canvas = canvasRef3.current; + let ctx = canvas.getContext('2d'); + + ctx.fillStyle = '#fd0'; + ctx.fillRect(0, 0, 75, 75); + ctx.fillStyle = '#6c0'; + ctx.fillRect(75, 0, 75, 75); + ctx.fillStyle = '#09f'; + ctx.fillRect(0, 75, 75, 75); + ctx.fillStyle = '#f30'; + ctx.fillRect(75, 75, 75, 75); + + ctx.fillStyle = '#fff'; + ctx.globalAlpha = 0.2; + + for (let i = 0; i < 6; i++) { + ctx.beginPath(); + ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true); + ctx.fill(); + } + } + + function demo4() { + let canvas = canvasRef4.current; + let ctx = canvas.getContext('2d'); + + ctx.fillStyle = 'rgb(255, 221, 0)'; + ctx.fillRect(0, 0, 200, 50); + ctx.fillStyle = 'rgb(102, 204, 0)'; + ctx.fillRect(0, 50, 200, 50); + ctx.fillStyle = 'rgb(0, 153, 255)'; + ctx.fillRect(0, 100, 200, 50); + ctx.fillStyle = 'rgb(255, 51, 0)'; + ctx.fillRect(0, 150, 200, 50); + + for (let i = 0; i < 10; i++) { + ctx.fillStyle = `rgba(255, 255, 255, ${(i + 1) / 10})`; + for (let j = 0; j < 4; j++) { + ctx.fillRect(10 + 18 * i, 5 + j * 50, 18, 40); + } + } + } + + function demo5() { + let canvas = canvasRef5.current; + let ctx = canvas.getContext('2d'); + + for (let i = 0; i < 10; i++) { + ctx.lineWidth = 1 + i; + ctx.beginPath(); + ctx.moveTo(5.5 + i * 14, 5.5); + ctx.lineTo(5.5 + i * 14, 140.5); + ctx.stroke(); + } + } + + function demo6() { + let canvas = canvasRef6.current; + let ctx = canvas.getContext('2d'); + let lineCap = ['butt', 'round', 'square']; + + ctx.strokeStyle = '#09f'; + ctx.beginPath(); + ctx.moveTo(10, 20); + ctx.lineTo(140, 20); + ctx.moveTo(10, 130); + ctx.lineTo(140, 130); + ctx.stroke(); + + ctx.strokeStyle = 'black'; + for (let i = 0; i < lineCap.length; i++) { + ctx.lineWidth = 15; + ctx.lineCap = lineCap[i]; + ctx.beginPath(); + ctx.moveTo(25 + i * 50, 20); + ctx.lineTo(25 + i * 50, 130); + ctx.stroke(); + } + } + + /** + * round 圆角线段 + * bevel 不让线段超过最大 + */ + function demo7() { + let canvas = canvasRef7.current; + let ctx = canvas.getContext('2d'); + let lineJoin = ['round', 'bevel', 'miter']; + + ctx.lineWidth = 10; + for (let i = 0; i < lineJoin.length; i++) { + ctx.lineJoin = lineJoin[i]; + ctx.beginPath(); + ctx.moveTo(-5, 5 + i * 40); + ctx.lineTo(35, 45 + i * 40); + ctx.lineTo(75, 5 + i * 40); + ctx.lineTo(115, 45 + i * 40); + ctx.lineTo(155, 5 + i * 40); + ctx.stroke(); + } + } + + /** + * setLineDash 虚线交替样式 + * lineDashOffset 偏移量 + */ + function demo8() { + let canvas = canvasRef8.current; + let ctx = canvas.getContext('2d'); + let offset = 0; + + function march() { + offset++; + + if (offset > 16) { + offset = 0; + } + _draw(); + setTimeout(march, 50); } - function demo2() { - let canvas = canvasRef2.current - let ctx = canvas.getContext('2d') - - for (let i = 0; i < 6; i++) { - for (let j = 0; j < 6; j++) { - ctx.strokeStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(255 - 42.5 * j)}, 0)` - ctx.beginPath() - ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true) - ctx.stroke() - } - } + function _draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.lineWidth = 2; + ctx.setLineDash([4, 2]); + ctx.lineDashOffset = -offset; + ctx.strokeRect(10, 10, 100, 100); } - function demo3() { - let canvas = canvasRef3.current - let ctx = canvas.getContext('2d') + march(); + } - ctx.fillStyle = '#fd0' - ctx.fillRect(0, 0, 75,75) - ctx.fillStyle = '#6c0' - ctx.fillRect(75, 0, 75, 75) - ctx.fillStyle = '#09f' - ctx.fillRect(0, 75, 75, 75) - ctx.fillStyle = '#f30' - ctx.fillRect(75, 75, 75, 75) + function demo9() { + let canvas = canvasRef9.current; + let ctx = canvas.getContext('2d'); - ctx.fillStyle = '#fff' - ctx.globalAlpha = 0.2 + let lineargradient = ctx.createLinearGradient(0, 0, 0, 150); + lineargradient.addColorStop(0, '#00abeb'); + lineargradient.addColorStop(0.5, '#fff'); + lineargradient.addColorStop(0.5, '#26c000'); + lineargradient.addColorStop(1, '#fff'); - for (let i = 0; i < 6; i++) { - ctx.beginPath() - ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true) - ctx.fill() - } - } + let radialgradient = ctx.createLinearGradient(0, 50, 0, 95); + radialgradient.addColorStop(0.5, '#000'); + radialgradient.addColorStop(1, 'rgba(0, 0, 0, 0'); - function demo4() { - let canvas = canvasRef4.current - let ctx = canvas.getContext('2d') + ctx.fillStyle = lineargradient; + ctx.strokeStyle = radialgradient; - ctx.fillStyle = 'rgb(255, 221, 0)' - ctx.fillRect(0, 0, 200, 50) - ctx.fillStyle = 'rgb(102, 204, 0)' - ctx.fillRect(0, 50, 200, 50) - ctx.fillStyle = 'rgb(0, 153, 255)' - ctx.fillRect(0, 100, 200, 50) - ctx.fillStyle = 'rgb(255, 51, 0)' - ctx.fillRect(0, 150, 200, 50) + ctx.fillRect(10, 10, 130, 130); + ctx.strokeRect(50, 50, 50, 50); + } - for (let i = 0; i < 10; i++) { - ctx.fillStyle = `rgba(255, 255, 255, ${(i + 1) / 10})` - for (let j = 0; j < 4; j++) { - ctx.fillRect(10 + 18 * i, 5 + j * 50, 18, 40) - } - } - } + function demo10() { + let canvas = canvasRef10.current; + let ctx = canvas.getContext('2d'); - function demo5() { - let canvas = canvasRef5.current - let ctx = canvas.getContext('2d') + let radgrad = ctx.createRadialGradient(45, 50, 10, 52, 50, 30); + radgrad.addColorStop(0, '#a7d30c'); + radgrad.addColorStop(0.9, '#019f62'); + radgrad.addColorStop(1, 'rgba(1, 159, 98, 0'); - for (let i = 0; i < 10; i++) { - ctx.lineWidth = 1 + i - ctx.beginPath() - ctx.moveTo(5.5 + i * 14, 5.5) - ctx.lineTo(5.5 + i * 14, 140.5) - ctx.stroke() - } - } + let radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50); + radgrad2.addColorStop(0, '#fff'); + radgrad2.addColorStop(0.75, '#ff0188'); + radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)'); - function demo6() { - let canvas = canvasRef6.current - let ctx = canvas.getContext('2d') - let lineCap = ['butt', 'round', 'square'] + let radgrad3 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90); + radgrad3.addColorStop(0, '#f4f201'); + radgrad3.addColorStop(0.8, '#00B5E2'); + radgrad3.addColorStop(1, '#00B5E2'); - ctx.strokeStyle = '#09f' - ctx.beginPath() - ctx.moveTo(10, 20) - ctx.lineTo(140, 20) - ctx.moveTo(10, 130) - ctx.lineTo(140, 130) - ctx.stroke() + ctx.fillStyle = radgrad3; + ctx.fillRect(0, 0, 150, 150); + ctx.fillStyle = radgrad2; + ctx.fillRect(0, 0, 150, 150); + ctx.fillStyle = radgrad; + ctx.fillRect(0, 0, 150, 150); + } - ctx.strokeStyle = 'black' - for (let i = 0; i < lineCap.length; i++) { - ctx.lineWidth = 15 - ctx.lineCap = lineCap[i] - ctx.beginPath() - ctx.moveTo(25 + i * 50, 20) - ctx.lineTo(25 + i * 50, 130) - ctx.stroke() - } - } + function demo11() { + let canvas = canvasRef11.current; + let ctx = canvas.getContext('2d'); - /** - * round 圆角线段 - * bevel 不让线段超过最大 - */ - function demo7() { - let canvas = canvasRef7.current - let ctx = canvas.getContext('2d') - let lineJoin = ['round', 'bevel', 'miter'] + // 创建 img,作为图案 + let img = new Image(); + img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png'; - ctx.lineWidth = 10 - for (let i = 0; i < lineJoin.length; i++) { - ctx.lineJoin = lineJoin[i] - ctx.beginPath() - ctx.moveTo(-5, 5 + i * 40) - ctx.lineTo(35, 45 + i * 40) - ctx.lineTo(75, 5 + i * 40) - ctx.lineTo(115, 45 + i * 40) - ctx.lineTo(155, 5 + i * 40) - ctx.stroke() - } - } + img.onload = function () { + let ptrn = ctx.createPattern(img, 'repeat'); + ctx.fillStyle = ptrn; + ctx.fillRect(0, 0, 150, 150); + }; + } - /** - * setLineDash 虚线交替样式 - * lineDashOffset 偏移量 - */ - function demo8() { - let canvas = canvasRef8.current - let ctx = canvas.getContext('2d') - let offset = 0 + function demo12() { + let canvas = canvasRef12.current; + let ctx = canvas.getContext('2d'); - function march() { - offset++ + ctx.beginPath(); + ctx.fillStyle = '#aaa'; + ctx.arc(50, 50, 30, 0, Math.PI * 2, true); + ctx.arc(50, 50, 15, 0, Math.PI * 2, true); + ctx.fill('evenodd'); + } - if (offset > 16) { - offset = 0 - } - _draw() - setTimeout(march, 50) - } + useEffect(() => { + demo1(); + demo2(); + demo3(); + demo4(); + demo5(); + demo6(); + demo7(); + demo8(); + demo9(); + demo10(); + demo11(); + demo12(); + }, []); - function _draw() { - ctx.clearRect(0, 0, canvas.width, canvas.height) - ctx.lineWidth = 2 - ctx.setLineDash([4, 2]) - ctx.lineDashOffset = -offset - ctx.strokeRect(10, 10, 100, 100) - } - - march() - } - - function demo9() { - let canvas = canvasRef9.current - let ctx = canvas.getContext('2d') - - let lineargradient = ctx.createLinearGradient(0, 0, 0, 150) - lineargradient.addColorStop(0, '#00abeb') - lineargradient.addColorStop(0.5, '#fff') - lineargradient.addColorStop(0.5, '#26c000') - lineargradient.addColorStop(1, '#fff') - - let radialgradient = ctx.createLinearGradient(0, 50, 0, 95) - radialgradient.addColorStop(0.5, '#000') - radialgradient.addColorStop(1, 'rgba(0, 0, 0, 0') - - ctx.fillStyle = lineargradient - ctx.strokeStyle = radialgradient - - ctx.fillRect(10, 10, 130, 130) - ctx.strokeRect(50, 50, 50, 50) - } - - function demo10() { - let canvas = canvasRef10.current - let ctx = canvas.getContext('2d') - - let radgrad = ctx.createRadialGradient(45, 50, 10, 52, 50, 30) - radgrad.addColorStop(0, '#a7d30c') - radgrad.addColorStop(0.9, '#019f62') - radgrad.addColorStop(1, 'rgba(1, 159, 98, 0') - - let radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50) - radgrad2.addColorStop(0, '#fff') - radgrad2.addColorStop(0.75, '#ff0188') - radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)') - - let radgrad3 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90) - radgrad3.addColorStop(0, '#f4f201') - radgrad3.addColorStop(0.8, '#00B5E2') - radgrad3.addColorStop(1, '#00B5E2') - - ctx.fillStyle = radgrad3 - ctx.fillRect(0, 0, 150, 150) - ctx.fillStyle = radgrad2 - ctx.fillRect(0, 0, 150, 150) - ctx.fillStyle = radgrad - ctx.fillRect(0, 0, 150, 150) - } - - function demo11() { - let canvas = canvasRef11.current - let ctx = canvas.getContext('2d') - - // 创建 img,作为图案 - let img = new Image() - img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png' - - img.onload = function () { - let ptrn = ctx.createPattern(img, 'repeat') - ctx.fillStyle = ptrn - ctx.fillRect(0, 0, 150, 150) - } - } - - function demo12() { - let canvas = canvasRef12.current - let ctx = canvas.getContext('2d') - - ctx.beginPath() - ctx.fillStyle = '#aaa' - ctx.arc(50, 50, 30, 0, Math.PI * 2, true) - ctx.arc(50, 50, 15, 0, Math.PI * 2, true) - ctx.fill('evenodd') - } - - useEffect(() => { - demo1() - demo2() - demo3() - demo4() - demo5() - demo6() - demo7() - demo8() - demo9() - demo10() - demo11() - demo12() - }, []) - - return ( -
- - - - - - - - - - - - -
- ) -} + return ( +
+ + + + + + + + + + + + +
+ ); +}; ``` ```js -``` \ No newline at end of file +``` diff --git a/docs/fea/canvas/font.md b/docs/fea/canvas/font.md index 08e339f..c0b8e12 100644 --- a/docs/fea/canvas/font.md +++ b/docs/fea/canvas/font.md @@ -5,6 +5,7 @@ nav: group: title: 💊 canvas order: 4 + path: /canvas --- ## 文字 @@ -13,65 +14,63 @@ group: import React, { useRef, useEffect } from 'react'; export default () => { - const canvasRef = useRef() - const canvasRef2 = useRef() - const canvasRef3 = useRef() + const canvasRef = useRef(); + const canvasRef2 = useRef(); + const canvasRef3 = useRef(); - // 填充文本 - function demo1() { - // 声明DOM - let canvas = canvasRef.current - let ctx = canvas.getContext('2d') + // 填充文本 + function demo1() { + // 声明DOM + let canvas = canvasRef.current; + let ctx = canvas.getContext('2d'); - ctx.shadowOffsetY = 8 - ctx.shadowOffsetX = 8 - ctx.shadowBlur = 3 - ctx.shadowColor = '#ccc' + ctx.shadowOffsetY = 8; + ctx.shadowOffsetX = 8; + ctx.shadowBlur = 3; + ctx.shadowColor = '#ccc'; - ctx.font = '40px serif' - ctx.fillText('1. 你是个智障!', 50, 50) - } + ctx.font = '40px serif'; + ctx.fillText('1. 你是个智障!', 50, 50); + } - function demo2() { - let canvas = canvasRef2.current - let ctx = canvas.getContext('2d') + function demo2() { + let canvas = canvasRef2.current; + let ctx = canvas.getContext('2d'); - ctx.font = '48px serif' - ctx.strokeText('2. hello world', 10, 50) - } + ctx.font = '48px serif'; + ctx.strokeText('2. hello world', 10, 50); + } - function demo3() { - let canvas = canvasRef3.current - let ctx = canvas.getContext('2d') + function demo3() { + let canvas = canvasRef3.current; + let ctx = canvas.getContext('2d'); - ctx.font = '40px serif' - ctx.textBaseline = 'top' - ctx.textAlign = 'start' - ctx.strokeText('hello world', 0, 100) - } + ctx.font = '40px serif'; + ctx.textBaseline = 'top'; + ctx.textAlign = 'start'; + ctx.strokeText('hello world', 0, 100); + } - useEffect(() => { - demo1() - demo2() - demo3() - }, []) + useEffect(() => { + demo1(); + demo2(); + demo3(); + }, []); - return ( -
- - - -
- ) -} + return ( +
+ + + +
+ ); +}; ``` ```ts window.onload = function () { - demo1() - demo2() - demo3() -} - - -``` \ No newline at end of file + demo1(); + demo2(); + demo3(); +}; +``` diff --git a/docs/fea/node/intro.md b/docs/fea/node/intro.md index 4d4c074..bc68b94 100644 --- a/docs/fea/node/intro.md +++ b/docs/fea/node/intro.md @@ -8,73 +8,80 @@ group: path: /node --- - # 💊 node -基于 chrome 的 V8引擎 封装的一个JavaScript运行环境,事件驱动、非阻塞IO进程模型,它能让js代码运行在服务端。 +基于 chrome 的 V8 引擎 封装的一个 JavaScript 运行环境,事件驱动、非阻塞 IO 进程模型,它能让 js 代码运行在服务端。 对于前端工程师来说具有极大的意义,也让前端工程师离全栈工程师更近了一步。 -对标产品为基于 rust、Tokio 的deno(destroy node),deno 具有更高的效率,并且原生就支持 typescript +对标产品为基于 rust、Tokio 的 deno(destroy node),deno 具有更高的效率,并且原生就支持 typescript ## 安装 -### 方法1 -#### 拉取nvm - - wget -qO- [https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh](https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh) | bash -#### 安装nvm +### 方法 1 + +#### 拉取 nvm + + + + - curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash - + + - sudo yum install -y nodejs + +#### 安装 nvm + ```javascript // 打开bash source ~/.bash_profile // 写入 node文件指向 -export NODE_HOME=/usr/local/tool/nodejs/node +export NODE_HOME=/usr/local/tool/nodejs/node export PATH=$NODE_HOME/bin:$PATH ``` - nvm install node(版本号)or nvm install stable - 方案2 - curl --silent --location [https://rpm.nodesource.com/setup_11.x](https://rpm.nodesource.com/setup_11.x)| sudo bash - -### 方法2 +### 方法 2 1. 第一步 -``` + +```js wget https://npm.taobao.org/mirrors/node/v12.16.1/node-v12.16.1-linux-x64.tar.gz ``` - 2. 第二步 + ``` tar -xvf node-v12.16.1-linux-x64.tar.gz yum install gcc gcc-c++ ``` - 3. 第三步 + ``` mv node-v12.16.1-linux-x64.tar.gz node ``` 4. 第四步 + ``` ln -s /usr/local/bin/node/bin/node /usr/bin/node ln -s /usr/local/bin/node/bin/npm /usr/bin/npm ln -s /usr/local/bin/node/bin/npx /usr/bin/npx ``` - ### 安装 GIT - - curl [https://setup.ius.io](https://setup.ius.io) | sh - - yum install -y git2u - - git --version - +- curl [https://setup.ius.io](https://setup.ius.io) | sh +- yum install -y git2u +- git --version ## cjs、esm、umd 的区别 -首先运行端的区别,cjs和esm只能运行在node端,而umd可以同时运行在node和浏览器端 +首先运行端的区别,cjs 和 esm 只能运行在 node 端,而 umd 可以同时运行在 node 和浏览器端 -1. cjs 即为 CommonJs, 属于早期的node规范,可以使用require进行引用,module.exports 导出。 -2. esm 即为 Es module,属于es6提出之后版本的新的规范,语法是可以用 import 引用,export default 导出。 -3. umd 即为 Universal Module Definition(通用模块定义),也就是最基本的可在浏览器和node端执行的 js 代码。 +1. cjs 即为 CommonJs, 属于早期的 node 规范,可以使用 require 进行引用,module.exports 导出。 +2. esm 即为 Es module,属于 es6 提出之后版本的新的规范,语法是可以用 import 引用,export default 导出。 +3. umd 即为 Universal Module Definition(通用模块定义),也就是最基本的可在浏览器和 node 端执行的 js 代码。 diff --git a/docs/fea/pattern/about.md b/docs/fea/pattern/about.md index d1eea1d..325dba7 100644 --- a/docs/fea/pattern/about.md +++ b/docs/fea/pattern/about.md @@ -5,11 +5,12 @@ nav: group: title: 💊 设计模式 order: 1 + path: /pattern --- ## 关于 -学习设计模式,是为了让你的代码减少亢余,能用健壮的代码去解决问题,提升可维护性与拓展性。 +学习设计模式,它是一种思维模式,目的是为了让代码减少亢余,能用比较结构化的代码去解决问题,提升可维护性与拓展性。 **想做靠谱开发,先学设计模式** diff --git a/docs/fea/pattern/action.md b/docs/fea/pattern/action.md index 5d61c20..0d8f579 100644 --- a/docs/fea/pattern/action.md +++ b/docs/fea/pattern/action.md @@ -5,6 +5,7 @@ nav: group: title: 💊 设计模式 order: 6 + path: /pattern --- ## 行为型 diff --git a/docs/fea/pattern/createType.md b/docs/fea/pattern/createType.md index 6f3e6af..33003ed 100644 --- a/docs/fea/pattern/createType.md +++ b/docs/fea/pattern/createType.md @@ -5,6 +5,7 @@ nav: group: title: 💊 设计模式 order: 2 + path: /pattern --- ## 创建型 diff --git a/docs/fea/pattern/structure.md b/docs/fea/pattern/structure.md index 87114de..4eee174 100644 --- a/docs/fea/pattern/structure.md +++ b/docs/fea/pattern/structure.md @@ -5,6 +5,7 @@ nav: group: title: 💊 设计模式 order: 4 + path: /pattern --- ## 结构型 @@ -15,7 +16,7 @@ group: 将一个类的接口转化为另外一个接口,以满足用户需求,使类之间接口不兼容问题通过适配器得以解决。 -案例:新来的大卫封装了个 **fetch** 请求库,但是公司以前的网络请求方法是基于 **XMLHttpRequest** 的,老板想大卫去改这已经写好的9999个接口的请求,大卫使用了适配器模式去兼容,如下: +案例:新来的大卫封装了个 **fetch** 请求库,但是公司以前的网络请求方法是基于 **XMLHttpRequest** 的,老板想大卫去改这已经写好的 9999 个接口的请求,大卫使用了适配器模式去兼容,如下: ```js // RequestUtil 请求库 @@ -81,7 +82,7 @@ function Ajax(type, url, data, success, failed){ // 发送post请求 xhr.send(data); } - + // 处理返回数据 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ @@ -136,20 +137,20 @@ Ajax('get', 'https://nicecoders.github.io', data, function(res){ ```jsx import React, { useRef, useState, useEffect } from 'react'; -import '@nicecode/css' +import '@nicecode/css'; class Modal { constructor(opt = {}) { - const { dom } = opt + const { dom } = opt; - this.dom = dom + this.dom = dom; } show() { this.dom.innerHTML = '卧槽'; - this.dom.style.display = 'block' - this.dom.style.width = '200px' - this.dom.style.textAlign = 'center' + this.dom.style.display = 'block'; + this.dom.style.width = '200px'; + this.dom.style.textAlign = 'center'; } hide() { @@ -159,65 +160,81 @@ class Modal { class DecoratorModal { constructor(_oldModal) { - this._oldModal = _oldModal + this._oldModal = _oldModal; } show() { - this._oldModal.show() + this._oldModal.show(); - this._oldModal.dom.innerHTML = '添加背景+文字减淡+圆角' - this._oldModal.dom.style.color = '#aaa' - this._oldModal.dom.style.borderRadius = '5px' + this._oldModal.dom.innerHTML = '添加背景+文字减淡+圆角'; + this._oldModal.dom.style.color = '#aaa'; + this._oldModal.dom.style.borderRadius = '5px'; } hide() { - this._oldModal.hide() + this._oldModal.hide(); } } export default () => { - const modalRef = useRef(null) - const [modal, setModal] = useState(null) + const modalRef = useRef(null); + const [modal, setModal] = useState(null); // 案例:原本有个按钮,新的需求要将按钮样式置灰,并且文案改为 快去登录 const openModal = () => { - modal.show() - } + modal.show(); + }; const hideModal = () => { - modal.hide() - } + modal.hide(); + }; const decoratorModal = () => { - let dom = new DecoratorModal(modal) + let dom = new DecoratorModal(modal); - setModal(dom) - } + setModal(dom); + }; const normalModal = () => { let dom = new Modal({ - dom: modalRef.current - }) + dom: modalRef.current, + }); - setModal(dom) - } + setModal(dom); + }; useEffect(() => { - normalModal() - }, []) + normalModal(); + }, []); let style = { margin: '0 6px', - } + }; return (
- - - - -
+ + + + +
- ) + ); }; ``` @@ -230,9 +247,9 @@ function funcDecorator(type) { return function (target, name, descriptor) { if (type === 'class') { target.prototype.show = () => { - console.log('装饰器处理后的类') - } - return target + console.log('装饰器处理后的类'); + }; + return target; /** * or * return class NButton { @@ -240,28 +257,29 @@ function funcDecorator(type) { * console.log('装饰器处理后') * } * } - **/ + **/ } else if (type === 'function') { - const old = descriptor.value - descriptor.value = function(...arg) { // 注意这里需要保留原this作用域,不能使用箭头函数 - console.log('----装饰器装饰函数----') + const old = descriptor.value; + descriptor.value = function (...arg) { + // 注意这里需要保留原this作用域,不能使用箭头函数 + console.log('----装饰器装饰函数----'); // 原函数 - return old.apply(this, arg) - } + return old.apply(this, arg); + }; } - } + }; } // 通过装饰器改变原有的 show 方法 // @funcDecorator('class') class Button { show() { - console.log('大卫的思想空间') + console.log('大卫的思想空间'); } @funcDecorator('function') mb() { - console.log('我是sb') + console.log('我是sb'); } } @@ -271,15 +289,10 @@ export default () => { // dom.show() // dom.mb() // console.log(dom) - }, []) - - return ( -
- 进阶案例:控制台查看输出结果 -
- ) -} + }, []); + return
进阶案例:控制台查看输出结果
; +}; ``` ### 代理模式 @@ -292,21 +305,21 @@ export default () => { import React, { useRef, useEffect } from 'react'; // 普通私密信息 -const baseInfo = ['name', 'age', 'career'] +const baseInfo = ['name', 'age', 'career']; // 最私密信息 -const privateInfo = ['avatar', 'phone'] +const privateInfo = ['avatar', 'phone']; // 规定礼物的数据结构由type和value组成 const present = { - type: '巧克力', - value: 60, -} + type: '巧克力', + value: 60, +}; // 相亲男方 const user = { - isValidated: true, - isVIP: false, -} + isValidated: true, + isVIP: false, +}; // 相亲女方 const girl = { @@ -330,53 +343,48 @@ const girl = { bottomValue: 50, // 记录最近一次收到的礼物 lastPresent: present, -} +}; // 掘金婚介所推出了小礼物功能 const JuejinLovers = new Proxy(girl, { - get: function(girl, key) { - - if((baseInfo.indexOf(key) !== -1) && !user.isValidated) { - alert('您还没有完成验证哦') - return + get: function (girl, key) { + if (baseInfo.indexOf(key) !== -1 && !user.isValidated) { + alert('您还没有完成验证哦'); + return; } // 此处我们认为只有验证过的用户才可以购买VIP - if(user.isValidated && privateInfo.indexOf(key) !== -1 && !user.isVIP) { - alert('只有VIP才可以查看该信息哦') - return + if (user.isValidated && privateInfo.indexOf(key) !== -1 && !user.isVIP) { + alert('只有VIP才可以查看该信息哦'); + return; } - return girl[key] + return girl[key]; }, - set: function(girl, key, val) { - + set: function (girl, key, val) { // 最近一次送来的礼物会尝试赋值给lastPresent字段 // 需要返回 boolean 判断是否赋值成功 - if(key === 'lastPresent') { - if(val.value < girl.bottomValue) { - alert('sorry,您的礼物被拒收了') - return false + if (key === 'lastPresent') { + if (val.value < girl.bottomValue) { + alert('sorry,您的礼物被拒收了'); + return false; } // 如果没有拒收,则赋值成功,同时并入presents数组 - girl.lastPresent = val - girl.presents = [...girl.presents, val] - return true + girl.lastPresent = val; + girl.presents = [...girl.presents, val]; + return true; } - } -}) + }, +}); export default () => { - useEffect(() => { - console.log(JuejinLovers.name) - JuejinLovers.lastPresent = present - console.log(JuejinLovers) - }, []) + console.log(JuejinLovers.name); + JuejinLovers.lastPresent = present; + console.log(JuejinLovers); + }, []); - return ( -
hi
- ) -} + return
hi
; +}; ``` diff --git a/docs/fea/webgl/Q&A.md b/docs/fea/webgl/Q&A.md index 325fc9e..abe6963 100644 --- a/docs/fea/webgl/Q&A.md +++ b/docs/fea/webgl/Q&A.md @@ -5,6 +5,7 @@ nav: group: title: 💊 webGL order: 100 + path: /webgl --- # 常见问题 diff --git a/docs/fea/webgl/intro.md b/docs/fea/webgl/intro.md index bc08037..634f101 100644 --- a/docs/fea/webgl/intro.md +++ b/docs/fea/webgl/intro.md @@ -5,6 +5,7 @@ nav: group: title: 💊 webGL order: 1 + path: /webgl --- # 基础 diff --git a/docs/fea/webgl/threeJS.md b/docs/fea/webgl/threeJS.md index 4d2ab0b..70d5057 100644 --- a/docs/fea/webgl/threeJS.md +++ b/docs/fea/webgl/threeJS.md @@ -5,6 +5,7 @@ nav: group: title: 💊 webGL order: 3 + path: /webgl --- # threeJS 入门 diff --git a/docs/fea/website/index.md b/docs/fea/website/index.md index 755bf3b..9ec234a 100644 --- a/docs/fea/website/index.md +++ b/docs/fea/website/index.md @@ -8,7 +8,7 @@ group: path: /website --- -## 💊 学习文档 +# 💊 学习文档 ### TS 学习 diff --git a/docs/interview/algorithms.md b/docs/interview/algorithms.md new file mode 100644 index 0000000..0a89299 --- /dev/null +++ b/docs/interview/algorithms.md @@ -0,0 +1,12 @@ +--- +nav: + title: 面试 + path: /interview +group: + title: 💊 面试题库 + order: 2 +--- + +# 算法题 + +参考链接: diff --git a/docs/interview/facetoface.md b/docs/interview/facetoface.md index 9d2f9c5..5b6c5c6 100644 --- a/docs/interview/facetoface.md +++ b/docs/interview/facetoface.md @@ -18,19 +18,14 @@ group: 举个例子: --------------------------------- -面试官好,我叫dev,18年毕业于东华理工大学软件工程,从大四开始就一直从事前端开发的工作 +> 面试官好,我叫 XX,18 年毕业于 XXX 大学软件工程,从大四开始就一直从事前端开发的工作 +> 我比较擅长的是 react 全家桶,平时开发的话,打包工具的话对 webpack 比较熟悉,自己有从 0-1 大型项目的经验和能力,包括前端项目的自动构建脚本编写,项目服务器发布,基本的 node 接口服务开发。服务器 Nginx 的配置,负载均衡,域名服务器的配置,和使用 pm2 的去做项目的守护进程管理全链路开发。 +> 在上家公司是 XXXX 的项目负责人,主要职责是负责从 0-1 视频编辑器的开发和后期维护,还有及时响应客户需求。在此期间还基于 yapi 搭建了一套接口自动化管理系统,目的是为了高效对接后端接口质量(自动化测试)和解放手动编写接口的工作(通过后端 swagger 文档自动生成包含 ts 注释的接口),其它还负责公司的 UI 组件库的部分开发 +> 除了开发相关的工作,还有一定的作为 Owner 的项目管理经验:比如需求评审,UI\UX 交互评审,负责小组项目排期,成员之间的协作开发,监督成员之间的 codeReview,敏捷开发推动项目进度等。 +> 另外我有自己的博客,主要是用来记录在工作中的一些心得,和碰到的问题和解决方案。同时去记录一些学到的新的知识,并把它分享到 sf、csdn、juejin 这类的技术平台上。 +> 在 github 上....做这件事的原因是,我感觉开源还挺有成就感也挺有趣的 -我比较擅长的是 react 全家桶,平时开发的话,打包工具的话对 webpack 比较熟悉,自己有从0-1大型项目的经验和能力,包括前端项目的自动构建脚本编写,项目服务器发布,基本的node接口服务开发。服务器Nginx 的配置,负载均衡,域名服务器的配置,和使用 pm2 的去做项目的守护进程管理全链路开发。 - -在上家公司是人工智能创意中心,视频编辑器的项目负责人,主要职责是负责从0-1视频编辑器的开发和后期维护,还有及时响应客户需求。在此期间还基于 yapi 搭建了一套接口自动化管理系统,目的是为了高效对接后端接口质量(自动化测试)和解放手动编写接口的工作(通过后端swagger文档自动生成包含ts注释的接口),其它还负责公司的UI组件库的部分开发 - -除了开发相关的工作,还有一定的作为Owner的项目管理经验:比如需求评审,UI\UX交互评审,负责小组项目排期,成员之间的协作开发,监督成员之间的codeReview,敏捷开发推动项目进度等。 - -另外我有自己的博客,主要是用来记录在工作中的一些心得,和碰到的问题和解决方案。同时去记录一些学到的新的知识,早期也发过一些文章再segmentfault和掘金上。 -在 github 上我还成立了一个自己的组织叫nicecode,主要是用来沉淀一些这些年工作中整合的一些能提升工作效率的方案,比如说:脚手架、git提交校验工具、敏感字过滤库,常见函数方法、还有开发过一款基于 vscode 的代码片段插件。前前后后写了10几个npm包了,做这件事的原因是,我感觉开源还挺有成就感也挺有趣的 - --------------------------------- +> 目前在学习... ## 如何粗略判断公司是否靠谱 @@ -46,11 +41,17 @@ group: 很推荐大家在准备面试的过程中,挖掘出自己擅长的技术内容,然后在面试的过程中,寻找机会引导面试官提问你擅长的技术点。 +## 你最近碰到什么挑战? + +**我(最近的一个时间)在做(怎样的一个产品/程序),这个产品/程序的目的是(帮助用户完成什么事),其中有一个(什么模块),为了实现(什么功能),用到了(什么技术),但是(遇到了什么挑战/难点/bug),我通过(怎样的手段)定位问题所在,问题出现的原因是(简要的点到技术点的描述),我在(至少两个资料来源)上找到了参考,最后基于(怎样的决策标准)决定采用(何种解决方法),运用了(哪种技术),最后成功解决了问题/实现了功能,结果是这个产品/程序(对用户,系统,性能,可用性,资源等产生了何种正面的影响)。下一步,我认为我应该研究(何种更先进的方式),进一步(怎样让产品/程序做得更好)。** + +之前将视频编辑器从 1.0 迁移到 2.0,目的是引用 vue3 和抛弃之前的遗留问题,比如说依赖包的杂糅和重,当时在考虑做视频编辑器的架构,是想直接写成个大组件,通过 props 参数来控制编辑器的功能,后面从性能和易用性来考虑,觉得还是将整体插件化更好,所以将整体架构改成可插拔式。在开发的过程中又发现关于数据传递板块如果通过传统的 props 或者是 vuex 的形式传递,使用起来会非常不方便,所以将它改成发布订阅模式来调用,将整体的数据放在一个 protocol 空间中,再通过各个控制面板的调用去触发,反馈到视频渲染层的监听器与其它对应插件的监听器上。最后实际应用中确实使用起来非常丝滑。这个编辑器的整体架构也使性能上提升了很多。 + ### 常见问题答复 1. 你什么时候入职? -在职的时候说:需要交接一下手续,大概1-2礼拜。 +在职的时候说:需要交接一下手续,大概 1-2 礼拜。 离职的时候说:确定录用的话,大概一周左右时间可以入职。 2. 为啥工作换的这么频繁? @@ -64,9 +65,10 @@ group: 4. 为什么你觉得可以胜任这份工作? 从三个角度去展开: -* 工作经历、项目背景与当前岗位的匹配度 -* 个人能力模型的匹配度 -* 突出过往的工作中取得的成绩,竞争力优势 + +- 工作经历、项目背景与当前岗位的匹配度 +- 个人能力模型的匹配度 +- 突出过往的工作中取得的成绩,竞争力优势 5. 你的期望薪资是多少? @@ -78,7 +80,7 @@ group: 7. 为啥没干多久就离职了? -两个方面,一个方面是和当初说好的不一样,公司目前使用vue,但是会用 react 重启新项目,我认为做一件事专精很重要。另一方面,加班比较多,项目上线冲进度加班是正常且合理的,但是经常周末需要加班,晚上10-11点走,CTO 倒排压缩开发时长不是很合理,生活和工作太不平衡,我不是很能接受 +两个方面,一个方面是和当初说好的不一样,公司目前使用 vue,但是会用 react 重启新项目,我认为做一件事专精很重要。另一方面,加班比较多,项目上线冲进度加班是正常且合理的,但是经常周末需要加班,晚上 10-11 点走,CTO 倒排压缩开发时长不是很合理,生活和工作太不平衡,我不是很能接受 ## 谈钱 @@ -92,3 +94,5 @@ group: ## 话术技巧参考 + + diff --git a/docs/interview/img/hooks.png b/docs/interview/img/hooks.png new file mode 100644 index 0000000..9dd3688 Binary files /dev/null and b/docs/interview/img/hooks.png differ diff --git a/docs/interview/javascript.md b/docs/interview/javascript.md index 4eaadf4..641d3cc 100644 --- a/docs/interview/javascript.md +++ b/docs/interview/javascript.md @@ -29,20 +29,19 @@ group: 2. instanceof 可以判断复杂引用数据类型,但是不能判断基本数据类型 3. typeof 能判断基本数据类型,在引用类型中只能判断 function -> 通用检测数据类型,可以采用Object.prototype.toString.call(),调用该方法,统一返回格式“[object Xxx]” 的字符串 +> 通用检测数据类型,可以采用 Object.prototype.toString.call(),调用该方法,统一返回格式“[object Xxx]” 的字符串 -### 3种强制类型转换两种隐式类型转换 +### 3 种强制类型转换两种隐式类型转换 - parseInt parseFloat number - == - === -### 数组方法pop() push() unshift() shift() - +### 数组方法 pop() push() unshift() shift() - push() 尾部添加 pop() 尾部删除 - unshift() 头部添加 shift() 头部删除 -### ajax请求 get 和 post 的区别 +### ajax 请求 get 和 post 的区别 ```text post: 1. 传参不同,请求参数放在虚拟载体里面(data对象)、2. 如果服务器端不介入干预,大小没有限制。3. 参数不会暴露在链接上,所以安全性更强,并且post的内容不会被缓存。4. 传参类型不做限制。 @@ -51,18 +50,23 @@ get: 1. 参数在链接上。2、url链接长度有限制,所以大小有限 ``` -### call 和 apply 的区别 +### bind、call 和 apply 的区别 -call可以允许多个参数入参,而apply只允许一个参数 +共同点:都是为了改变 this 的指向而存在 -- object.call(this, obj1,obj2,obj3) -- object.apply(this, argument) +不同点: + +- call 可以接受多个参数:object.call(this, obj1,obj2,obj3) +- bind 可以接受多个参数:object.bind(this, obj1,obj2,obj3) +- apply 接受两个参数,一个是指向的对象,一个是需要传递的参数 object.apply(this, ${Array}) +- call 和 apply 改变上下文 this 指向后,立刻执行该函数,而 bind 不执行 + +使用场景:如果参数数量不确定就用 apply,确定就用 call. ### ajax 请求时,如何解析 json 数据 - -- 使用eval parse,介于安全性考虑 使用parse 更靠谱 -- eval 可以解析任何字符串,parse只解析json格式的字符串 +- 使用 eval parse,介于安全性考虑 使用 parse 更靠谱 +- eval 可以解析任何字符串,parse 只解析 json 格式的字符串 ### 添加 删除 替换 插入到某个节点的方法 @@ -71,65 +75,61 @@ call可以允许多个参数入参,而apply只允许一个参数 - obj.replaceChild() - obj.removeChild() - - ### javascript 同源策略 - 一段脚本只能读取来自同一来源的穿考核文档的属性,同源:指主机名,协议和端口号的组合 ### 编写一个 b 继承 a 的方法 - ```javascript function A(name) { this.name = name; - this.sayHello = function() { - alert(this.name+ "say hello!") - } + this.sayHello = function () { + alert(this.name + 'say hello!'); + }; } function B(name, id) { - this.temp = A - this.temp(name) - delete this.temp - this.id = id - this.checkId = function(ID) {alert(this.id == ID)} + this.temp = A; + this.temp(name); + delete this.temp; + this.id = id; + this.checkId = function (ID) { + alert(this.id == ID); + }; } ``` - ### 如何阻止事件冒泡和默认事件 - ```javascript function stopBubble(e) { - if (e && e.stopPropagation) { - e.stopPropgation () - } else { - window.event.cancelBubble = true - } - return false + if (e && e.stopPropagation) { + e.stopPropgation(); + } else { + window.event.cancelBubble = true; + } + return false; } ``` - ### 谈谈 this 对象的理解 -- this只在调用的时候发生指向确认,它指向什么取决于在什么地方调用。this 指向的就是调用函数的那个对象。 -- this 一般情况下: 是指全局对象global, 如果作为方法调用,就指向这个对象 +- this 只在调用的时候发生指向确认,它指向什么取决于在什么地方调用。this 指向的就是调用函数的那个对象。 +- this 一般情况下: 是指全局对象 global, 如果作为方法调用,就指向这个对象 - 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window -- 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象(箭头函数则指向window) +- 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象(箭头函数则指向 window) - 对于 new 的方式来说,this 被永远绑定在构造函数上面,不会被任何方式改变 this ```js class Test { constructor() { - console.log(this) + console.log(this); } } export default () => { - let demo = new Test() -} + let demo = new Test(); +}; ``` ### `location.replace()`与`location.assign()`区别 @@ -138,117 +138,65 @@ export default () => { location.replace() 的 url 不会出现在 history 中 ``` - ### DOM 操作 ```html -// 创建节点 -createDocumentFragment() -createElement() -createTextNode() - -// 添加 移除 替换 插入 -appendChild() -removeChild() -replaceChild() -insertBefore() - -// 查找 -getElementsByTagName() -getElementsByName() -getElementsByClassName() -getElementById() -querySelector() -querySelectorAll() +// 创建节点 createDocumentFragment() createElement() createTextNode() // 添加 +移除 替换 插入 appendChild() removeChild() replaceChild() insertBefore() // 查找 +getElementsByTagName() getElementsByName() getElementsByClassName() +getElementById() querySelector() querySelectorAll() ``` -### JS设置css样式的几种方式 +### JS 设置 css 样式的几种方式 ```html -/* 1.直接设置style属性 */ -element.style.height = '100px'; - -/* 2.直接设置属性 */ -element.setAttribute('height', '100px'); - -/* 3.使用setAttribute设置style属性 */ -element.setAttribute('style', 'height: 100px !important'); - -/* 4.使用setProperty设置属性,通过第三个参数设置important */ -element.style.setProperty('height', '300px', 'important'); - -/* 5.设置cssText */ +/* 1.直接设置style属性 */ element.style.height = '100px'; /* 2.直接设置属性 */ +element.setAttribute('height', '100px'); /* 3.使用setAttribute设置style属性 */ +element.setAttribute('style', 'height: 100px !important'); /* +4.使用setProperty设置属性,通过第三个参数设置important */ +element.style.setProperty('height', '300px', 'important'); /* 5.设置cssText */ element.style.cssText += 'height: 100px !important'; ``` - ### 阻止默认行为 ```html -function stopDefault( e ) { - // 阻止默认浏览器动作(W3C) - if ( e && e.preventDefault ) { - e.preventDefault(); - } else { - // IE中阻止函数器默认动作的方式 - window.event.returnValue = false; - } - return false; -} +function stopDefault( e ) { // 阻止默认浏览器动作(W3C) if ( e && +e.preventDefault ) { e.preventDefault(); } else { // +IE中阻止函数器默认动作的方式 window.event.returnValue = false; } return false; } ``` ### 阻止冒泡 ```html -function stopBubble(e) { - // 如果提供了事件对象,则这是一个非IE浏览器 - if ( e && e.stopPropagation ) { - // 因此它支持W3C的stopPropagation()方法 - e.stopPropagation(); - } else { - // 否则,我们需要使用IE的方式来取消事件冒泡 - window.event.cancelBubble = true; - } -} +function stopBubble(e) { // 如果提供了事件对象,则这是一个非IE浏览器 if ( e && +e.stopPropagation ) { // 因此它支持W3C的stopPropagation()方法 +e.stopPropagation(); } else { // 否则,我们需要使用IE的方式来取消事件冒泡 +window.event.cancelBubble = true; } } ``` -### Ajax交互过程 +### Ajax 交互过程 ```html 创建XMLHttpRequest对象,也就是创建一个异步调用对象. 创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息. -设置响应HTTP请求状态变化的函数. -发送HTTP请求. -获取异步调用返回的数据. +设置响应HTTP请求状态变化的函数. 发送HTTP请求. 获取异步调用返回的数据. 使用JavaScript和DOM实现局部刷新. ``` -### 考察知识点最广的JS面试题 +### 考察知识点最广的 JS 面试题 [https://www.cnblogs.com/xxcanghai/p/5189353.html](https://www.cnblogs.com/xxcanghai/p/5189353.html) ```html -function Foo() { - getName = function () { alert(1); } - return this; -} -Foo.getName = function () { alert(2); } -Foo.prototype.getName = function () { alert(3); } -var getName = function () { alert(4); } -function getName () { alert(5); } - - -/* 写出输出 */ -Foo.getName(); 3 -getName(); 5 -Foo().getName(); 3 -getName(); -new Foo.getName(); -new Foo().getName(); -new new Foo().getName(); +function Foo() { getName = function () { alert(1); } return this; } Foo.getName += function () { alert(2); } Foo.prototype.getName = function () { alert(3); } +var getName = function () { alert(4); } function getName () { alert(5); } /* +写出输出 */ Foo.getName(); 3 getName(); 5 Foo().getName(); 3 getName(); new +Foo.getName(); new Foo().getName(); new new Foo().getName(); ``` -### splice和slice你能说说有啥用和区别吗 +### splice 和 slice 你能说说有啥用和区别吗 1. splice:是可以实现数组的增删改查、只对数组生效,会改变原数组 2. slice:不光可以截取数组,也可以截取字符串,不会改变原数组 @@ -258,8 +206,8 @@ new new Foo().getName(); 1. 类数组不具备数组的方法(slice、splice、filter) 2. 类数组是一个普通对象,数组类型是 Array +### JS 数组深浅拷贝 -### JS数组深浅拷贝 #### 浅拷贝 把一个对象的第一层拷贝到新的对象上去,只拷贝基本数据类型 @@ -272,8 +220,8 @@ var new_arr = arr.slice(); new_arr[0] = 'new'; -console.log(arr) // ["old", 1, true, null, undefined] -console.log(new_arr) // ["new", 1, true, null, undefined] +console.log(arr); // ["old", 1, true, null, undefined] +console.log(new_arr); // ["new", 1, true, null, undefined] // concat 实现 var arr = ['old', 1, true, null, undefined]; @@ -282,8 +230,8 @@ var new_arr = arr.concat(); new_arr[0] = 'new'; -console.log(arr) // ["old", 1, true, null, undefined] -console.log(new_arr) // ["new", 1, true, null, undefined] +console.log(arr); // ["old", 1, true, null, undefined] +console.log(new_arr); // ["new", 1, true, null, undefined] ``` #### 深拷贝 @@ -292,62 +240,69 @@ console.log(new_arr) // ["new", 1, true, null, undefined] ```javascript // 简单版:不能拷贝 函数、undefined、symbol 、循环引用的对象 -var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]; +var arr = ['old', 1, true, ['old1', 'old2'], { old: 1 }]; var new_arr = JSON.parse(JSON.stringify(arr)); new_arr[0] = 'new'; new_arr[3][0] = 'new1'; -console.log(arr) // ["old", 1, true, ['old1', 'old2'], {old: 1}] -console.log(new_arr) // ["new", 1, true, ['new1', 'old2'], {old: 1}] +console.log(arr); // ["old", 1, true, ['old1', 'old2'], {old: 1}] +console.log(new_arr); // ["new", 1, true, ['new1', 'old2'], {old: 1}] // 复杂版,可以完美拷贝 var deepCopy = function (obj) { - if (typeof obj !== 'object') { - return + if (typeof obj !== 'object') { + return; + } + var newObj = obj instanceof Array ? [] : {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + newObj[key] = + typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } - var newObj = obj instanceof Array ? [] : {}; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; - } - } - return newObj -} + } + return newObj; +}; ``` ### 数组去重 ```javascript // filter + indexOf -function unique (arr) { - var res = arr.filter(function (item, index, array) { - return array.indexOf(item) === index; - }) - return res; +function unique(arr) { + var res = arr.filter(function (item, index, array) { + return array.indexOf(item) === index; + }); + return res; } //filter + sort -function unique (arr) { - return arr.concat().sort().filter(function (item, index, array) { - return !index || item !== array[index - 1]; - }) +function unique(arr) { + return arr + .concat() + .sort() + .filter(function (item, index, array) { + return !index || item !== array[index - 1]; + }); } // ES6 -function uniqu3 (arr) { - return [... new Set(arr)]; +function uniqu3(arr) { + return [...new Set(arr)]; } ``` -### + +### + ### 找出数组中的最大值 + ```javascript // reduce var arr = [6, 4, 1, 8, 2, 11, 3]; -function max (prev, next) { - return Math.max(prev, next) +function max(prev, next) { + return Math.max(prev, next); } console.log(arr.reduce(max)); @@ -360,54 +315,60 @@ console.log(Math.max.apply(null, arr)); //ES6 var arr = [6, 4, 1, 8, 2, 11, 3]; -function max (arr) { - return Math.max(...arr); +function max(arr) { + return Math.max(...arr); } console.log(max(arr)); ``` - ### 数组扁平化 + ```javascript var arr = [1, [2, [3, 4]]]; function flatten(arr) { + while (arr.some((item) => Array.isArray(item))) { + arr = [].concat(...arr); + } - while (arr.some(item => Array.isArray(item))) { - arr = [].concat(...arr); - } - - return arr; + return arr; } -console.log(flatten(arr)) +console.log(flatten(arr)); ``` - ### 数据的基本类型 + ```javascript 1. symbol 2. string 3. number 4. null 5. boolean 6. undefind ``` - ### 数据类型判断 + > 关键语句:Object.prototype.toString.call(value) => [object ${Boolean Number String Function Array Date RegExp Object Error Null }] ```javascript var class2type = {}; -'Boolean Number String Function Array Date RegExp Object Error Null Undefined'.split(' ').map((item, index) => { +'Boolean Number String Function Array Date RegExp Object Error Null Undefined' + .split(' ') + .map((item, index) => { class2type['[object ' + item + ']'] = item.toLowerCase(); -}) + }); -function type (obj) { - return typeof obj === 'object' || typeof obj === 'function' ? - class2type[{}.toString.call(obj)] || 'object' : typeof obj; +function type(obj) { + return typeof obj === 'object' || typeof obj === 'function' + ? class2type[{}.toString.call(obj)] || 'object' + : typeof obj; } ``` ### 防抖 + +原理:创建一个闭包,然后通过调用创建好的函数和入参去执行 +应用场景是为了防止用户误触,而产生多次事件的触发,根本就是为了节省性能消耗 + ```javascript /* * func:需要调用的函数 @@ -441,6 +402,24 @@ var debounce = function (func, wait, immediate) { } ``` +## 节流 + +使用场景:把动作中的持续调用设置为固定时间内的调用,比如滚动事件,鼠标移入移出。 + +```js +const throttle = (fuc, delay) => { + let time = null; + + return function () { + const currentTime = new Date(); + + if (currentTime - time > delay) { + fuc.appy(this, arguments); + time = currentTime; + } + }; +}; +``` ### 四则运算符 @@ -454,16 +433,12 @@ var debounce = function (func, wait, immediate) { ![image.png](./img/this.png) - ### ‘==’ 和 ‘===’ 有什么区别 - == 对比类型不一样会进行类型转换,而 ’===‘ 不会,下图为 ’==‘ 的判断步骤: - ![image.png](./img/equal.png) - ### 什么是闭包? 定义:函数 A 中有一个函数 B,函数 B 可以访问 A 的变量,那么函数 B 就是闭包。 @@ -471,6 +446,7 @@ var debounce = function (func, wait, immediate) { - 闭包就是引用其他函数内部变量的函数 1. 循环中使用闭包解决 `var` 定义函数的问题 + ```javascript 方法1 for (var i = 1; i <= 5; i++) { @@ -509,7 +485,7 @@ for (let i = 1; i <= 5; i++) { ```js const useCount = () = { let count = 0 - + const getCount = () => { return count } @@ -531,65 +507,74 @@ const useCount = () = { 4. 回调函数 ```js -const fn = (cb: (name: string) => void) => { - let name = 'nicecode' - cb(name) -} +const fn = (cb: (name: string) => void) => { + let name = 'nicecode'; + cb(name); +}; ``` ### 如何理解原型?如何理解原型链? -原型的本质就是一个对象,我们创建一个构造函数的时候,它自动会带上一个prototype属性,这个属性就指向原型对象。它的作用就是用来提供基于函数原型继承的共享属性 +原型的本质就是一个对象,我们创建一个构造函数的时候,它自动会带上一个 prototype 属性,这个属性就指向原型对象。它的作用就是用来提供基于函数原型继承的共享属性 当读取实例的属性获取不到时,如果找不到,就会查找与对象关联的原型中的属性,还找不到就会去找原型的原型,一直到顶层,这样的一层层的关系嵌套称为**原型链** -1. 每一个对象都有**__proto__**这是浏览器早期为了让我们能访问 prototype。 -2. _ _proto__ 的 constructor(构造函数)里面有 prototype。 -3. _ _proto__ 下面有几个方法:hasOwnProperty 、toString、toLocalString、valueOf、isPrototypeOf -4. 原型的 `constructor` 属性指向构造函数,构造函数又通过 `prototype` 属性指回原型,但是并不是所有函数都具有这个属性,`Function.prototype.bind()` 就没有这个属性。 +1. 每一个对象都有****proto****这是浏览器早期为了让我们能访问 prototype。 +2. \_ \_proto\_\_  的 constructor(构造函数)里面有 prototype。 +3. \_ \_proto\_\_  下面有几个方法:hasOwnProperty 、toString、toLocalString、valueOf、isPrototypeOf +4. 原型的  `constructor`  属性指向构造函数,构造函数又通过  `prototype`  属性指回原型,但是并不是所有函数都具有这个属性,`Function.prototype.bind()`  就没有这个属性。 ![image.png](./img/prototype.png) ## 理解 promise -promise 的出现是为了解决回调地狱(callback hell),它的其他API有: +promise 的出现是为了解决回调地狱(callback hell),它的其他 API 有: -1. all(处理所有promise事件回调的合集) +1. all(处理所有 promise 事件回调的合集) ```js -let p1 = new Promise(function(resolve, reject) { resolve('ok1') }) -let p2 = new Promise(function(resolve, reject) { resolve('ok2') }) -let p3 = Promise.reject('err') +let p1 = new Promise(function (resolve, reject) { + resolve('ok1'); +}); +let p2 = new Promise(function (resolve, reject) { + resolve('ok2'); +}); +let p3 = Promise.reject('err'); -let res = Promise.all([p1,p2]).then(res => console.log(res)) +let res = Promise.all([p1, p2]).then((res) => console.log(res)); // ['ok1', 'ok2'] -let res2 = Promise.all([p1,p2,p3]).then(res => console.log(res)).catch(err => console.error(err)) +let res2 = Promise.all([p1, p2, p3]) + .then((res) => console.log(res)) + .catch((err) => console.error(err)); // err ``` 2. race(获取最快的返回结果) ```js -let p1 = new Promise(function(resolve, reject) { setTimeout(() => resolve('ok1'), 500) }) -let p2 = new Promise(function(resolve, reject) { setTimeout(() => resolve('ok2'), 1500) }) +let p1 = new Promise(function (resolve, reject) { + setTimeout(() => resolve('ok1'), 500); +}); +let p2 = new Promise(function (resolve, reject) { + setTimeout(() => resolve('ok2'), 1500); +}); -let res = Promise.race([p1,p2]).then(res => console.log(res)) // ok1 +let res = Promise.race([p1, p2]).then((res) => console.log(res)); // ok1 ``` -3. allSettled(忽视reject) +3. allSettled(忽视 reject) -避免promise队列中有 reject 忽视。 +避免 promise 队列中有 reject 忽视。 ### 手写一个 promise ```jsx import React, { useEffect, useState } from 'react'; -const PENDING = 'PENDING'; // 处理中 -const FULFILLED = 'FULFILLED'; // 已完成 -const REJECTED = 'REJECTED'; // 已拒绝 - +const PENDING = 'PENDING'; // 处理中 +const FULFILLED = 'FULFILLED'; // 已完成 +const REJECTED = 'REJECTED'; // 已拒绝 class Prom { constructor(executor) { @@ -602,61 +587,58 @@ class Prom { let resolve = (val) => { if (this.status === PENDING) { - this.status = FULFILLED - this.value = val + this.status = FULFILLED; + this.value = val; } - } + }; let reject = (err) => { if (this.status === PENDING) { - this.status = REJECTED - this.error = err + this.status = REJECTED; + this.error = err; } - } + }; try { - // 立即执行,将 resolve 和 reject 函数传给使用者 - executor(resolve, reject) - } catch (error) { - // 发生异常时执行失败逻辑 - reject(error) - } + // 立即执行,将 resolve 和 reject 函数传给使用者 + executor(resolve, reject); + } catch (error) { + // 发生异常时执行失败逻辑 + reject(error); + } } then(onFulfilled, onReject) { if (this.status === FULFILLED) { - onFulfilled(this.value) + onFulfilled(this.value); } if (this.status === REJECTED) { - onReject(this.reason) + onReject(this.reason); } } } -export default() => { - const [text, setText] = useState(PENDING) +export default () => { + const [text, setText] = useState(PENDING); useEffect(() => { const promise = new Prom((resolve, reject) => { resolve('成功'); }).then( (data) => { - setText(data) - console.log('手写promise', data) + setText(data); + console.log('手写promise', data); }, (err) => { - setText(err) - console.log('faild', err) - } - ) - }, []) - - return ( -
{text}
- ) -} + setText(err); + console.log('faild', err); + }, + ); + }, []); + return
{text}
; +}; ``` ## async 和 await @@ -666,6 +648,7 @@ export default() => { ## 柯里化 特点: + 1. 组合函数:可以将函数的逻辑简单化,并且达到更细粒度的代码拆分和复用 2. 延迟执行:可以延迟执行最后一个参数执行的时间,在期间做一些其他逻辑的执行,剩余的到后面再决定 3. 简单化函数:将参数从多参数拆为单参数,让接口简洁,更容易使用 @@ -674,41 +657,80 @@ export default() => { import React, { useEffect } from 'react'; function curry(a: number) { - return function(b: number) { - return function(offset: number) { - return a + b + offset - } - } + return function (b: number) { + return function (offset: number) { + return a + b + offset; + }; + }; } export default () => { - curry(1)(2)(3) + curry(1)(2)(3); - return ( -
柯里化函数
- ) -} + return
柯里化函数
; +}; ``` -## event loop +## event loop 事件循环机制 -js 执行的过程中,会创建对应的执行上下文放入栈中,我们称之为执行栈,其中执行栈中的任务又会分为宏任务和微任务。按照流程执行就是一次宏任务的进行结束之后,查看是否有微任务,执行微任务,微任务执行完毕,再一次执行宏任务,就是所谓的 event loop +js 执行的过程中,会创建对应的执行上下文放入栈中,我们称之为 **执行栈**,其中执行栈中的任务又会分为宏任务和微任务。按照流程执行就是一次宏任务的进行结束之后,查看是否有微任务,执行微任务,微任务执行完毕,再一次执行宏任务,就是所谓的 event loop -宏任务大概有:setTimeout()、setInterval()、setImmediate()、I/O、用户交互操作,UI渲染 +宏任务大概有:setTimeout()、setInterval()、setImmediate()、I/O、用户交互操作,UI 渲染 微任务则有:promise.then()、promise.catch()、new MutationObserver、process.nextTick() +```js +// 抽现转具象的描述事件循环 +{ + tasks: [ + { + script: '主代码块', + }, + { + script: 'innter的click回调函数', + microtasks: [ + { + script: 'Promise', + }, + { + script: 'MutationObserver', + }, + ], + }, + { + script: 'outer的click回调函数', + microtasks: [ + { + script: 'Promise', + }, + { + script: 'MutationObserver', + }, + ], + }, + { + script: 'setTimeout', + }, + { + script: 'setInterval', + }, + ]; +} +``` + ## 堆、栈的区别 1. 基本数据类型一般内存小,放在栈中;引用数据类型一般内存大,放在堆中 2. 栈的垃圾回收是执行环境结束立即释放,而堆需要所有引用结束才会释放 3. 一般来说栈的效率要高于堆 -## v8的垃圾回收机制 +## v8 的垃圾回收机制 -执行js的过程中,根据对象的存活时间进行不同的分代,然后根据不同的分代采用不同的回收算法 +执行 js 的过程中,根据对象的存活时间进行不同的分代,然后根据不同的分代采用不同的回收算法 -新生代的空间换时间 scavenge 算法是:1. 执行的过程中将空间分为 From 和 To 两块,2. 判断是否满足存活条件,存活的将变量复制到另一个空间,3. 不存活的直接清理。4. 将From 和 To 空间交换,如此循环往复 +新生代的空间换时间 scavenge 算法是:1. 执行的过程中将空间分为 From 和 To 两块,2. 判断是否满足存活条件,存活的将变量复制到另一个空间,3. 不存活的直接清理。4. 将 From 和 To 空间交换,如此循环往复。 + +另外就是新生代的内存为 8M 左右,属于一个短期生命变量储存的区域,如果在执行新生代算法标记的过程中,发现某个变量多次出现,就会移交到老生代垃圾回收算法区 老生代的标记清除和整理,运行的时候将活跃的变量标记,并进行整理到内存的一端,移除那些不活跃的空间进行释放回收 @@ -730,7 +752,7 @@ js 执行的过程中,会创建对应的执行上下文放入栈中,我们 ### 4. (unknown): Script error -当未捕获的 JavaScript 错误(通过window.onerror处理程序引发的错误,而不是捕获在try-catch中)被浏览器的跨域策略限制时,会产生这类的脚本错误。这是一种浏览器安全措施,旨在防止跨域传递数据,否则将不允许进行通信。 +当未捕获的 JavaScript 错误(通过 window.onerror 处理程序引发的错误,而不是捕获在 try-catch 中)被浏览器的跨域策略限制时,会产生这类的脚本错误。这是一种浏览器安全措施,旨在防止跨域传递数据,否则将不允许进行通信。 ### 5. TypeError: Object doesn’t support property @@ -756,6 +778,6 @@ js 执行的过程中,会创建对应的执行上下文放入栈中,我们 当您尝试访问未定义的变量或超出当前范围的变量时,会引发此错误。 -## 参考文章 +## 参考文章 diff --git a/docs/interview/performance.md b/docs/interview/performance.md index 4236e89..519a048 100644 --- a/docs/interview/performance.md +++ b/docs/interview/performance.md @@ -18,11 +18,11 @@ eval 的作用是将用户输入的字符串转化为可执行的代码,类似 严格模式下的变量 **重复声明** 等操作会抛出一些隐藏的错误。 ```javascript -'use strict' +'use strict'; var obj = { a: '1', - a: '2' -} + a: '2', +}; // 抛出错误 syntax error ``` @@ -52,30 +52,23 @@ child_process.exec('ls', function (err, data) { ## 7. 临时文件 - 创建文件时,处理上传的文件要注意,这些文件可能会吃掉你的磁盘所有空间。 - > 使用 Streams。 ## 8. 加密 Web 应用 - 用 https 代替 http,请求的过程可以添加签名头。 - ## 9. Reflected Cross Site Scripting - 也就是跨站脚本攻击,就是但用户发送一段数据,如果在未做任何处理的情况下直接插入 DOM,这可能会出现安全问题,例如: - ```javascript //用户输入的数据中带脚本,如果不做处理,会被执行。 Im human