首页
统计
关于
正则表达式手册
Search
1
React中编写css的几种方式
48 阅读
2
rollup.js的个人理解
41 阅读
3
【整理】Nginx基础知识
37 阅读
4
前端工程化的思考
36 阅读
5
package.json的配置参考
35 阅读
默认分类
服务器端
前端工程化
react
vue
nodejs
js+
html&css
问题集录
临时
dylin
gu
登录
/
注册
Search
标签搜索
问题
前端工程化
基础知识
css
数据库
docker
nginx
rollup.js
react
golang
js
性能优化
js基础
dylin
累计撰写
21
篇文章
累计收到
1
条评论
首页
栏目
默认分类
服务器端
前端工程化
react
vue
nodejs
js+
html&css
问题集录
临时
dylin
gu
页面
统计
关于
正则表达式手册
搜索到
4
篇与
的结果
2023-12-24
【整理】开发注意事项-1
开发注意事项考虑 边界值 :如果要展示一个列表,就要考虑列表为空、列表长度超过一页的情况;如果展示的是文字,则要考虑文字为空、文字超长的情况;访问a.b.c时,a或b是否可能为undefined。考虑 特殊场景 :如交互状态(hover、disabled、文字提示)、浮点数计算精度(使用utils方法)、防重复提交、分辨率兼容、移动设备兼容、事件冒泡、防抖和节流;考虑 需求变更和功能拓展 :需求变更是不可避免的,那就要在开发的时候考虑到哪些地方容易变(数值、变量),哪些不容易变(框架、模式),提前做好设计规划,减少因需求变更造成的大规模重构。考虑代码 可读性 :复杂方法标注用途、复杂逻辑解释清楚、修改他人代码先理解上下文并做好自测。保持优化代码的好习惯:所有不合理的问题,都是可以改的,代价大,就细致谋划,不要搁置,避免埋雷。代码越短就越好吗?实际的业务书写中,如果减少10%的代码换来的是可读性变差,那并不推荐这么做。我们推荐的是,在保证可读性的前提下,尽可能让代码变少。 // bad 三元嵌套三元不利于可读性 let message = (age < 3) ? 'Hi, baby!' : (age < 80) ? 'Hello!' : 'What an unusual age!'; // good if (age < 3) { message = 'Hi, baby!'; } else if (age < 80) { message = 'Hello!'; } else { message = 'What an unusual age!'; } // bad if (company == 'Netscape') { return true; } else { return false; } // good return company === 'Netscape';魔法值的问题魔法值,也叫做魔法数值、魔法数字,通常是指在代码编写时莫名出现的数字, 无法直接判断数值代表的含义,必须通过联系代码上下文分析才可以明白, 严重降低了代码的可读性。除数字之外,代码中作为key值的常量字符串也被认为是魔法值, 尽管其表示含义比数值较为清晰,但是仍然会产生不规范问题。 // 魔法值举例 if(flag === '5'){ ....... } if (businessType === 101){ ....... }通常会采用枚举类型来解决魔法值问题,由于JS中没有枚举类型,可以使用对象字面量的方式来模拟枚举,如下: const BusinessTypeEnum = { SYSTEM: 0, // 系统 CRM: 1, // CRM JXC: 2, // JXC UNKNOWN: 404, // 未知对象类型 CUSTOMER_MANAGEMENT: 100, // 客户管理 CUSTOMER: 101, // 客户 CUSTOMER_FOCUS: 102, // 重点客户 CUSTOMER_DEAL: 103, // 成交客户 CUSTOMER_FOLLOW: 104, // 跟进客户 CUSTOMER_PUBLIC: 105 // 客户公海池 } if (businessType === BusinessTypeEnum.CUSTOMER){ ....... }采用枚举的另外一个好处,当某个值因为需求迭代需求变更时,我们只需要在枚举中将该值替换,并不需要在全局搜素替换。程序中的电车难题如图,当一辆电车快速驶来,无论图上的人采取哪种选择,似乎都是错误的。但是,在程序中出现预期之外的错误必须要导致一个负面结果时,一定要选择代价最小的。举个例子: 某同学开发了一个新手引导弹窗功能,该功能有个透明的全屏遮罩,只有当新手引导结束时,遮罩才会消失。由于程序中存在一处逻辑判断不严谨,导致在特定情况下全屏遮罩不能被关闭,然后整个系统都不能被点击了。一个简单的新手引导功能却引发了系统不可用的严重故障,这是非常大的代价。通过上述例子去分析,系统不可用的负面影响远大于新手引导不可用。因此,我们应该修改逻辑判断方案,当程序脱离预期执行时,直接去关闭新手引导。 // before if (step === 0) { dialog.close() } else { dialog.show() } // after if ([1, 2, 3].includes(step)) { dialog.show() } else { dialog.close() }我们无法保证自己写的代码没有任何差错,但是我们可以提前考虑,万一发生预期之外的错误,我们要如何处理来让损失最低。不要让用户等待由用户触发的交互操作,应立即给予响应。立即响应不等于立即呈现数据,有些异步操作,无法立即呈现数据给用户,但应马上给予loading提示,告知用户数据正在处理中。下面的代码中,用户点击编辑按钮时,会先发起一个异步请求,拿到数据结果后再显示弹窗。这个短暂且没有任何提示的等待,会让用户认为是程序卡顿,体验不畅,间接诱导用户重复点击按钮。正确的做法应该是先展示弹窗,再去请求数据。三元和if该怎么选? // 如果条件表达式后面跟的是返回值,建议使用三元运算,如下方的例子,就可以优先考虑使用三元运算 // good a > b ? 1 : 2 // bad if (a > b) { return 1 } else { return 2 } // 其他复杂的分支代码,写成三元可能并不利于阅读,建议使用if语句,如下面的例子 // good if (a > b && b !== 0) { val = a + b } else { val = a - b } // bad a > b && b !== 0 ? val = a + b : val = a - bwhile和for该怎么选?for循环往往是用来遍历一个固定长度的可迭代对象,遍历的次数一定是<=可迭代对象的长度,如数组遍历、对象遍历等等;for和while在绝大部分场景下都可以互换,只是部分场景下,使用while会更符合我们的直觉。while循环往往用于 不定次数的条件执行 ,即达到目标条件就终止,但我们事先并不知道达到这个目标条件需要进行多少次执行。举个例子,我们希望从1开始,取前10个能整除3或5的数字,参考如下代码: let numArr = [] let i = 1 while (numArr.length < 10) { if (i % 3 === 0 || i % 5 === ) { numArr.push(i) } i++ }while在某些场景下,可以代替递归函数。比如我们希望得到100以内的斐波那契数列: // 使用递归 function fib (prev = 0, next = 1) { if (next < 100) { return [next, ...fib(next, prev + next)] } return [] } // 使用while functon fib2 (n = 100) { let prev = 0 let next = 1 let result = [] while (next < n) { result.push(next) const temp = prev prev = next next = next + temp } return result }上面的例子很难用for循环去实现,因为我们并不知道100以内存在多少个斐波那契数字,但知道终止条件是数字必须小于100,因此更适合用while循环来实现。再来说说递归和while,递归往往在代码量上来看是简洁的,但本质上它是一个N层的函数嵌套,所以直觉上不易理解,且耗性能(不考虑尾递归优化的前提下);while循环只有一层嵌套,所以直觉上更容易理解,且性能更优。这里并不是说递归不好,不推荐大家使用,一来性能并不是大家首先要考虑的问题,二来while只能在部分场景中来代替递归。
2023年12月24日
34 阅读
0 评论
0 点赞
2023-12-12
package.json的配置参考
package.json的配置参考package.json文件是Node.js项目中的一个重要配置文件,用于存储项目的元数据和各种配置信息。以下是一些常见的 package.json配置项:{ "name": "my-project", // 项目名称,遵循npm的命名规范 "private":true,//如果设置为 true,npm 将拒绝发布此包。 "version": "1.0.0", // 项目版本号,遵循semver规范 "description": "A short description of your project", // 项目描述 "main": "index.js", // 项目的入口文件 "bin": { "my-cli": "./bin/my-cli.js" // 如果你想让npm install -g全局安装后,可以通过命令行直接运行某个文件,可以在这里配置 }, "scripts": { "start": "node index.js", // 启动项目的命令 "test": "jest", // 测试命令 "lint": "eslint .", // 代码风格检查命令 "build": "webpack --config webpack.prod.js", // 构建生产环境的命令 "dev": "webpack serve --config webpack.dev.js" // 开发服务器启动命令 }, "dependencies": { "express": "^4.17.1", // 项目运行所依赖的模块 "axios": "^0.21.1" // 其他依赖模块 }, "devDependencies": { "jest": "^27.0.0", // 开发依赖的测试框架 "eslint": "^7.0.0", // 开发依赖的代码风格检查工具 "webpack": "^5.0.0", // 开发依赖的打包工具 "webpack-cli": "^4.0.0", // webpack的命令行工具 "webpack-merge": "^5.0.0" // 用于合并webpack配置文件 }, "peerDependencies": { "react": "^17.0.0" // 同等依赖,表示你的包需要和其他包一起使用,且版本需要匹配 }, "optionalDependencies": { "fsevents": "^2.0.0" // 可选依赖,如果无法安装则不会报错 }, "engines": { "node": ">=14.0.0", // 项目所依赖的Node.js版本范围 "npm": ">=6.0.0" // 项目所依赖的npm版本范围 }, "browserslist": [ "> 0.2%", // 目标浏览器版本范围 "not dead", // 不包括已经废弃的浏览器 "not ie <= 11" // 不包括IE 11及以下版本 ], "files": [ "dist", // 发布的npm包中包含的文件和目录 "src" ], "author": "Your Name <your.email@example.com>", // 作者信息 "license": "ISC", // 许可证信息 "repository": { "type": "git", "url": "git+https://github.com/your-username/my-project.git" // 项目仓库地址 }, "bugs": { "url": "https://github.com/your-username/my-project/issues" // 项目问题跟踪地址 }, "homepage": "https://github.com/your-username/my-project#readme", // 项目主页或文档地址 "keywords": [ "example", "project" // 项目的关键词列表 ], "publishConfig": { "registry": "https://your-custom-registry.com" // 自定义的npm仓库地址 }, "config": { "port": "8080" // 自定义配置,可以通过npm_package_config_port在代码中获取 }, "directories": { "lib": "lib", // 指示库文件的位置 "test": "test" // 指示测试文件的位置 }, "types": "./index.d.ts", // TypeScript的类型定义文件 "workspaces": [ "packages/*" // 如果你的项目是一个monorepo,这里可以配置工作区的位置 ], // 其他可能的配置项... }配置具体描述:name:项目的名称。名称的长度应小于或等于 214 个字符。不能以点(.)或下划线(_)开头。不能包含大写字母(因为 npm 包的 URL 是基于这个名称生成的)。名称应尽可能简短且语义化。version:项目的版本号,遵循语义化版本规范(semver)。description:项目的简短描述。main:项目的入口文件,通常是 JavaScript 文件。当其他文件通过 require() 引入你的项目时,会加载这个文件。scripts:项目的 npm 脚本,可以包含各种启动、测试、构建等命令。dependencies:项目运行所依赖的模块列表。这些依赖会被安装到生产环境。devDependencies:项目开发过程中需要的依赖,但不会在生产环境中使用。peerDependencies:同等依赖,表示你的包需要和其他包一起使用,且版本需要匹配。optionalDependencies:可选依赖,如果无法安装则不会报错。engines:指定项目所依赖的 Node.js 和 npm 的版本范围。browserslist:指定项目的目标浏览器版本,用于工具如 Autoprefixer、Babel 等。bin:指定可执行文件的位置,以便 npm install -g 时可以全局安装。files:指定在发布 npm 包时需要包含的文件列表。author:项目的作者信息。license:项目的许可证信息,如 MIT、BSD 等。repository:项目的仓库地址,如 GitHub 仓库。bugs:项目问题提交地址,通常是 GitHub issue 页面的链接。homepage:项目的主页或文档地址。keywords:项目的关键词列表,用于 npm 搜索。publishConfig:发布时使用的配置,如自定义的 npm 仓库地址。config:用于配置脚本中使用的环境变量。directories:指定项目目录的用途,如 lib 表示库文件的位置,test 表示测试文件的位置。types 或 typings:对于 TypeScript 项目,指定类型定义文件的位置。workspaces:对于 monorepo(多包仓库),指定工作区的位置。private:如果设置为 true,npm 将拒绝发布此包。sideEffects:对于 webpack 等打包工具,指定模块是否有副作用(即是否每次导入时都需要执行)。os:指定模块可以在哪些操作系统上运行。cpu:指定模块可以在哪些 CPU 架构上运行。exports:定义一个包的子路径的入口点,允许其他包使用更细粒度的导入语句。module:指定 ES6 模块入口点,用于支持 ES6 模块的打包工具。browser:指定在浏览器环境中使用的入口点。unpkg 和 jsdelivr:指定用于通过 unpkg 或 jsdelivr CDN 服务的文件路径。resolutions:用于覆盖依赖项中的特定子依赖项的版本。bundleDependencies 或 bundledDependencies:列出在发布包时应该被打包的依赖项。man:指定 man 手册文件的位置。contributors:项目的贡献者列表。funding:指定项目的资金赞助信息。
2023年12月12日
35 阅读
0 评论
0 点赞
2023-12-12
前端模块化——CommonJS、AMD、CMD、ESM
前端模块化——CommonJS、AMD、CMD、ESM前端模块化的概念:前端最初是没有模块化的,都是通过script引入,然后这个script引入的文件就会被全部加载,开发者需要看这个完整的script,才能知道这个文件的作用。模块化就是一个单独的script文件就是一个独立的模块,通过向外暴露特定的导出变量和函数,开发者不用关心文件里的其它内容是怎么实现的,提高了代码的复用率和开发效率。模块化的基础是js函数。前端模块化的发展历程:前端没有模块化-nodejs出现(node使用commonjs实现前端模块化)-CommonJS用同步的方式加载模块,在浏览器里限于网络原因,就需要使用异步加载。所以出现了AMDjs和CMD(他们都是为了解决异步加载的问题)-后来的ESM,新的浏览器标准,之前的amd和cmd只是补丁,esm是重新定义了标准,成为浏览器和服务器通用的模块解决方案其模块功能主要由两个命令构成:export和 import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。结语 commonjs是旧的方式,amd和cmd是commonjs的补丁。esm是新的标准,未来是esm的。commonjscommonjs用同步的方式加载模块。主要是在node里使用,是服务器端使用方法。有四个重要的环境变量为模块化的实现提供支持:module、exports、require、global。实际使用时,用 module.exports定义当前模块对外输出的接口(不推荐直接用 exports),用 require加载模块。exports和 module.export区别:module.export: 每个模块内部,module变量代表当前模块,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实就是加载该模块的exports属性。既可以使用 .语法,也可以使用 =直接赋值。exports:为了方便,node为每个模块提供了一个exports变量,指向module.exports。这等同于在每个模块头部,有这么一行代码:var exports = module.exports;所以不能直接将exports指向一个值,这会切断 exports 与 module.exports 的联系(但是可以用module.exports来指向一个值)./demo.js var age = 7; var sayHello= function (name) { return "hello " + name; }; exports = age; //不要这么干。这么做会切断exports与module.exports的联系 AMDCommonJS用同步的方式加载模块。在服务端,模块文件都存放在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。AMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。这里介绍用require.js实现AMD规范的模块化:用 require.config()指定引用路径等,用 definde()定义模块,用 require()加载模块。首先我们需要引入require.js文件和一个入口文件main.js。main.js中配置 require.config()并规定项目中用到的基础模块。 /** 网页中引入require.js及main.js **/ <script src="js/require.js" data-main="js/main"></script> /** main.js 入口文件/主模块 **/ // 首先用config()指定各模块路径和引用名 require.config({ baseUrl: "js/lib", paths: { "jquery": "jquery.min", //实际路径为js/lib/jquery.min.js "underscore": "underscore.min", } }); // 执行基本操作 require(["jquery","underscore"],function($,_){ // some code here });ES6 ModuleES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export和 import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。 /** 定义模块 math.js **/ var basicNum = 0; var add = function (a, b) { return a + b; }; export { basicNum, add }; /** 引用模块 **/ import { basicNum, add } from './math'; function test(ele) { ele.textContent = add(99 + basicNum); }总结CommonJs、AMD、CMD 是js模块化开发的规范,对应的实现是Node.js、require.js、sea.jsCommonJs主要针对服务端,AMD/CMD/ESModule主要针对浏览器端,容易混淆的是AMD/CMD。(顺便提一下,针对服务器端和针对浏览器端有什么本质的区别呢?服务器端一般采用同步加载文件,也就是说需要某个模块,服务器端便停下来,等待它加载再执行。这里如果有其他后端语言,如java。而浏览器端要保证效率,需要采用异步加载,这就需要一个预处理,提前将所需要的模块文件并行加载好。)AMD/CMD区别,虽然都是并行加载js文件,但还是有所区别,AMD是预加载,在并行加载js文件同时,还会解析执行该模块(因为还需要执行,所以在加载某个模块前,这个模块的依赖模块需要先加载完成);而CMD是懒加载,虽然会一开始就并行加载js文件,但是不会执行,而是在需要的时候才执行。(1)加载方式:AMD异步加载,CMD同步加载。(2)依赖声明:AMD需要在模块定义时声明依赖,CMD可以在需要时再引入依赖。(3)适用环境:AMD更适用于浏览器环境,CMD更适用于服务器端环境。(4)实现工具:RequireJS是AMD规范的主要实现,而SeaJS是CMD规范的主要实现。AMD/CMD的优缺点.一个的优点就是另一个的缺点, 可以对照浏览。AMD优点:加载快速,尤其遇到多个大文件,因为并行解析,所以同一时间可以解析多个文件。AMD缺点:并行加载,异步处理,加载顺序不一定,可能会造成一些困扰,甚至为程序埋下大坑。CMD优点:因为只有在使用的时候才会解析执行js文件,因此,每个JS文件的执行顺序在代码中是有体现的,是可控的。CMD缺点:执行等待时间会叠加。因为每个文件执行时是同步执行(串行执行),因此时间是所有文件解析执行时间之和,尤其在文件较多较大时,这种缺点尤为明显。(PS:重新看这篇文章,发现这里写的不是很准确。确切来说,JS是单线程,所有JS文件执行时间叠加在AMD和CMD中是一样的。但是CMD是使用时执行,没法利用空闲时间,而AMD是文件加载好就执行,往往可以利用一些空闲时间)CommonJS 和 ES Module 区别:CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用如何使用?CommonJs 的话,因为 NodeJS 就是它的实现,所以使用 node 就行,也不用引入其他包。AMD则是通过 <script>标签引入require.js,CMD则是引入sea.js
2023年12月12日
27 阅读
0 评论
0 点赞
2023-12-12
前端工程化的思考
前端工程化定义前端工程化。是一种将软件工程的方法和思想应用于前端开发的实践,它旨在提高开发效率、降低开发成本、保证代码质量,这包括使用构建工具、实行模块化和组件化、自动化和持续集成等技术。前端工程化关注于开发流程的规范化、标准化,以及通过工具和框架解决前端开发和前后端协作中的问题。例如,使用脚手架工具、代码规范和格式化、热更新和Mock数据、自动化测试和持续部署等都是前端工程化的体现。模块化。指的是将复杂的程序或系统拆分成多个独立的模块,每个模块负责特定的功能,这些模块可以单独开发、测试和维护,模块化有助于提高代码的可维护性、复用性和管理性。在前端开发中,模块化通过将代码拆分为小的、独立的文件来实现,这些文件通过统一的拼装和加载来协同工作。JavaScript的模块化规范,如CommonJS,定义了模块的作用域和加载机制,有助于避免全局作用域的污染和提高代码的复用率。组件化。是模块化的一种表现形式,它专注于用户界面的拆分和维护。组件化将页面结构、样式和行为分离成独立的组件,每个组件都有自己的工程目录和所需资源,组件之间可以自由组合,形成完整的页面。这种方法的优点在于提高代码的复用性和维护性,同时也方便了多人协作和项目的扩展。总的来说,前端工程化、模块化和组件化共同促进了前端开发的效率和质量,它们是现代前端开发中不可或缺的部分。前端工程化是指将前端开发中的项目管理、构建、测试、部署等环节进行规范化和自动化,以提高开发效率、代码质量和团队协作能力的一种开发方式。具体来说,前端工程化涉及以下几个主要方面:项目架构:对项目的文件组织结构、模块划分、代码规范等进行规范化。良好的项目架构可以提高代码的可维护性和可扩展性。版本控制:使用版本控制系统(如Git)对代码进行管理,实现多人协作、版本回退、分支管理等功能,保证代码的版本和历史可追溯。自动化构建:使用构建工具(如Webpack、Gulp)将源码编译、压缩、合并、打包等操作自动化处理,以生成可部署或上线的最终代码。组件化与模块化:通过将页面拆分成一个个独立的组件和模块,可以更加灵活地组合和复用代码,提升开发效率和代码可维护性。组件化是在设计层面上,对于UI的拆分;而模块化是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。自动化测试:自动化测试可以大大提升测试效率,减少人为错误。前后端分离与全栈工程化:前后端分离已经成为了现代Web开发的主流架构,前端和后端可以独立开发、独立部署、独立测试,大大提升了开发效率和产品质量。同时,全栈工程化的思想也在逐渐普及,即前后端使用统一的工程化标准和流程,进一步提升团队协作效率。前端工程化的目标是提升团队协作效率、提高代码质量、降低维护成本,并使前端开发更加规范和可持续。同时,它也能够适应快速迭代、多平台适配的现代前端开发需求。
2023年12月12日
36 阅读
0 评论
1 点赞