[timeline title="经典语录" type="small" start="梦开始的地方" end="新的一年开始"][item date="2022-04-15"] PUAPUAPUAPUAPUAPUAPUA。[/item][item date="2022-04-15"] 正常的社会并不是黑白分明、非此即彼的，有时善与善也会发生冲突。[/item][item date="2022-03-12"] 若不接受自己的卑微与渺小，我们很难发自内心地去尊重他人。[/item][item date="2022-02-14"] 人的野心是没有穷尽的，所以，不要成为纯粹的工具人。[/item][item date="2022-01-12"] 为什么害怕独处？因为人在独处的时候，总是会听到心灵深处的声音。[/item][item date="2021-12-12"] 我们只需要活好今天，因为永恒由每个今天构成，每个今天都可以触摸永恒。[/item][item date="2021-11-13"] 不要对人性抱以过高的期待，永远要警惕人性深处的幽暗，法治的前提就是对人性败坏的假设。[/item][item date="2021-10-14"] 人最大的痛苦，就是无法跨越“知道”和“做到”的鸿沟。[/item][item date="2021-9-12"] 低级的快乐来自放纵，高级的快乐来自克制。[/item][item date="2021-8-12"] 个知识越贫乏的人，越是拥有一种莫名奇怪的勇气和自豪感。 [/item][/timeline]
tsconfig.json配置项详解compilerOptions: 编译器的选项，如语言版本、目标 JavaScript 版本、生成的 sourcemap 等。include: 指定需要编译的文件路径或文件夹路径。exclude: 指定不需要编译的文件路径或文件夹路径。files: 指定需要编译的文件列表。extends: 指定继承自另一个 tsconfig.json 文件。compileOnSave : 指定是否在保存时编译文件。buildOnSave: 指定是否在保存时编译文件。target：编译目标 JavaScript 版本，可以是 “ES3”，“ES5” 或 “ES2015” 等。module：指定模块系统，可以是 “CommonJS”，“AMD” 或 “System” 等。sourceMap：是否生成 sourcemap 文件。outDir：编译输出目录。rootDir：设置项目的根目录。strict：是否开启严格类型检查。noImplicitAny：是否禁止隐式 any 类型。lib：指定要包含在编译中的库文件，如 “es2015”。paths: 指定模块路径别名。baseUrl: 指定基础目录。jsx: 指定 JSX 的处理方式。allowJs: 是否允许编译 JavaScript 文件。checkJs: 是否检查 JavaScript 文件。declaration: 是否生成声明文件。declarationMap: 是否生成声明文件的 sourcemap。emitDecoratorMetadata: 是否支持装饰器。experimentalDecorators: 是否支持实验性装饰器。listEmittedFiles: 是否列出所有输出的文件。listFiles: 是否列出所有编译过的文件。locale: 指定本地化语言。mapRoot: 指定 sourcemap 文件的根目录。moduleResolution: 指定模块解析策略。noEmit: 是否禁止输出 JavaScript 代码。noEmitHelpers: 是否禁止输出辅助函数。noEmitOnError: 是否在发生错误时禁止输出 JavaScript 代码。noImplicitReturns: 是否禁止隐式返回。noUnusedLocals: 是否检查未使用的局部变量。noUnusedParameters: 是否检查未使用的参数。preserveConstEnums: 是否保留 const 枚举。pretty: 是否格式化输出的 JavaScript 代码。removeComments: 是否移除注释。skipLibCheck: 是否跳过检查库文件。sourceRoot: 指定源文件的根目录。suppressExcessPropertyErrors: 是否禁止过多属性错误。suppressImplicitAnyIndexErrors: 是否禁止隐式 any 类型索引错误。typeRoots: 指定类型声明文件的根目录。types: 指定需要包含在编译中的类型声明文件。watch: 是否监视文件变化并重新编译。里面包含了一些常用的tsconfig选项以及注解：{ "compilerOptions": { "allowUnreachableCode": true, // 不报告执行不到的代码错误。 "allowUnusedLabels": false, // 不报告未使用的标签错误 "alwaysStrict": false, // 以严格模式解析并为每个源文件生成 "use strict"语句 "baseUrl": ".", // 工作根目录 "experimentalDecorators": true, // 启用实验性的ES装饰器 "jsx": "react", // 在 .tsx文件里支持JSX "sourceMap": true, // 是否生成map文件 "module": "commonjs", // 指定生成哪个模块系统代码 "noImplicitAny": false, // 是否默认禁用 any "removeComments": true, // 是否移除注释 "types": [ //指定引入的类型声明文件，默认是自动引入所有声明文件，一旦指定该选项，则会禁用自动引入，改为只引入指定的类型声明文件，如果指定空数组[]则不引用任何文件 "node", // 引入 node 的类型声明 ], "paths": { // 指定模块的路径，和baseUrl有关联，和webpack中resolve.alias配置一样 "src": [ //指定后可以在文件之直接 import * from 'src'; "./src" ], }, "target": "ESNext", // 编译的目标是什么版本的 "outDir": "./dist", // 输出目录 "declaration": true, // 是否自动创建类型声明文件 "declarationDir": "./lib", // 类型声明文件的输出目录 "allowJs": true, // 允许编译javascript文件。 "lib": [ // 编译过程中需要引入的库文件的列表 "es5", "es2015", "es2016", "es2017", "es2018", "dom" ] }, // 指定一个匹配列表（属于自动指定该路径下的所有ts相关文件） "include": [ "src/**/*" ], // 指定一个排除列表（include的反向操作） "exclude": [ "demo.ts" ], // 指定哪些文件使用该配置（属于手动一个个指定文件） "files": [ "demo.ts" ] }
ESLint 配置文件关于 ESLint 介绍，以及在项目中如何配置，请参考WebStorm + React 项目，配置 ESLint。配置文件ESLint 支持几种格式的配置文件，如果同一个目录下有多个配置文件，ESLint 只会使用一个。优先级顺序如下：JavaScript - 使用 .eslintrc.js 然后输出一个配置对象。YAML - 使用 .eslintrc.yaml 或 .eslintrc.yml 去定义配置的结构。JSON -使用 .eslintrc.json 去定义配置的结构，ESLint 的 JSON 文件允许 JavaScript 风格的注释。Deprecated -使用 .eslintrc，可以使 JSON 也可以是 YAML。package.json - 在 package.json 里创建一个 eslintConfig 属性，在那里定义你的配置。配置规则格式规则格式是<规则名称>: <告警级别>，告警级别分为三种:"0"表示忽略问题，等同于"off";"1"表示给出警告，等同于"warn";"2"表示直接报错，等同于"error"。详细规则说明/** * AlloyTeam ESLint 规则 - React * * 包含所有 ESLint 规则，以及所有 eslint-plugin-react 规则 * 使用 babel-eslint 作为解析器 * * @fixable 表示此配置支持 --fix * @off 表示此配置被关闭了，并且后面说明了关闭的原因 */ module.exports = { extends: [ './index.js', ], plugins: [ 'react' ], rules: { // 布尔值类型的 propTypes 的 name 必须为 is 或 has 开头 // @off 不强制要求写 propTypes 'react/boolean-prop-naming': 'off', // 一个 defaultProps 必须有对应的 propTypes // @off 不强制要求写 propTypes 'react/default-props-match-prop-types': 'off', // 组件必须有 displayName 属性 // @off 不强制要求写 displayName 'react/display-name': 'off', // 禁止在自定义组件中使用一些指定的 props // @off 没必要限制 'react/forbid-component-props': 'off', // 禁止使用一些指定的 elements // @off 没必要限制 'react/forbid-elements': 'off', // 禁止使用一些指定的 propTypes // @off 不强制要求写 propTypes 'react/forbid-prop-types': 'off', // 禁止直接使用别的组建的 propTypes // @off 不强制要求写 propTypes 'react/forbid-foreign-prop-types': 'off', // 禁止使用数组的 index 作为 key // @off 太严格了 'react/no-array-index-key': 'off', // 禁止使用 children 做 props 'react/no-children-prop': 'error', // 禁止使用 dangerouslySetInnerHTML // @off 没必要限制 'react/no-danger': 'off', // 禁止在使用了 dangerouslySetInnerHTML 的组建内添加 children 'react/no-danger-with-children': 'error', // 禁止使用已废弃的 api 'react/no-deprecated': 'error', // 禁止在 componentDidMount 里面使用 setState // @off 同构应用需要在 didMount 里写 setState 'react/no-did-mount-set-state': 'off', // 禁止在 componentDidUpdate 里面使用 setState 'react/no-did-update-set-state': 'error', // 禁止直接修改 this.state 'react/no-direct-mutation-state': 'error', // 禁止使用 findDOMNode 'react/no-find-dom-node': 'error', // 禁止使用 isMounted 'react/no-is-mounted': 'error', // 禁止在一个文件创建两个组件 // @off 有一个 bug https://github.com/yannickcr/eslint-plugin-react/issues/1181 'react/no-multi-comp': 'off', // 禁止在 PureComponent 中使用 shouldComponentUpdate 'react/no-redundant-should-component-update': 'error', // 禁止使用 ReactDOM.render 的返回值 'react/no-render-return-value': 'error', // 禁止使用 setState // @off setState 很常用 'react/no-set-state': 'off', // 禁止拼写错误 'react/no-typos': 'error', // 禁止使用字符串 ref 'react/no-string-refs': 'error', // 禁止在组件的内部存在未转义的 >, ", ' 或 } 'react/no-unescaped-entities': 'error', // @fixable 禁止出现 HTML 中的属性，如 class 'react/no-unknown-property': 'error', // 禁止出现未使用的 propTypes // @off 不强制要求写 propTypes 'react/no-unused-prop-types': 'off', // 定义过的 state 必须使用 // @off 没有官方文档，并且存在很多 bug： https://github.com/yannickcr/eslint-plugin-react/search?q=no-unused-state&type=Issues&utf8=%E2%9C%93 'react/no-unused-state': 'off', // 禁止在 componentWillUpdate 中使用 setState 'react/no-will-update-set-state': 'error', // 必须使用 Class 的形式创建组件 'react/prefer-es6-class': [ 'error', 'always' ], // 必须使用 pure function // @off 没必要限制 'react/prefer-stateless-function': 'off', // 组件必须写 propTypes // @off 不强制要求写 propTypes 'react/prop-types': 'off', // 出现 jsx 的地方必须 import React // @off 已经在 no-undef 中限制了 'react/react-in-jsx-scope': 'off', // 非 required 的 prop 必须有 defaultProps // @off 不强制要求写 propTypes 'react/require-default-props': 'off', // 组件必须有 shouldComponentUpdate // @off 没必要限制 'react/require-optimization': 'off', // render 方法中必须有返回值 'react/require-render-return': 'error', // @fixable 组件内没有 children 时，必须使用自闭和写法 // @off 没必要限制 'react/self-closing-comp': 'off', // @fixable 组件内方法必须按照一定规则排序 'react/sort-comp': 'error', // propTypes 的熟悉必须按照字母排序 // @off 没必要限制 'react/sort-prop-types': 'off', // style 属性的取值必须是 object 'react/style-prop-object': 'error', // HTML 中的自闭和标签禁止有 children 'react/void-dom-elements-no-children': 'error', // @fixable 布尔值的属性必须显式的写 someprop={true} // @off 没必要限制 'react/jsx-boolean-value': 'off', // @fixable 自闭和标签的反尖括号必须与尖括号的那一行对齐 'react/jsx-closing-bracket-location': [ 'error', { nonEmpty: false, selfClosing: 'line-aligned' } ], // @fixable 结束标签必须与开始标签的那一行对齐 // @off 已经在 jsx-indent 中限制了 'react/jsx-closing-tag-location': 'off', // @fixable 大括号内前后禁止有空格 'react/jsx-curly-spacing': [ 'error', { when: 'never', attributes: { allowMultiline: true }, children: true, spacing: { objectLiterals: 'never' } } ], // @fixable props 与 value 之间的等号前后禁止有空格 'react/jsx-equals-spacing': [ 'error', 'never' ], // 限制文件后缀 // @off 没必要限制 'react/jsx-filename-extension': 'off', // @fixable 第一个 prop 必须得换行 // @off 没必要限制 'react/jsx-first-prop-new-line': 'off', // handler 的名称必须是 onXXX 或 handleXXX // @off 没必要限制 'react/jsx-handler-names': 'off', // @fixable jsx 的 children 缩进必须为四个空格 'react/jsx-indent': [ 'error', 4 ], // @fixable jsx 的 props 缩进必须为四个空格 'react/jsx-indent-props': [ 'error', 4 ], // 数组中的 jsx 必须有 key 'react/jsx-key': 'error', // @fixable 限制每行的 props 数量 // @off 没必要限制 'react/jsx-max-props-per-line': 'off', // jsx 中禁止使用 bind // @off 太严格了 'react/jsx-no-bind': 'off', // 禁止在 jsx 中使用像注释的字符串 'react/jsx-no-comment-textnodes': 'error', // 禁止出现重复的 props 'react/jsx-no-duplicate-props': 'error', // 禁止在 jsx 中出现字符串 // @off 没必要限制 'react/jsx-no-literals': 'off', // 禁止使用 target="_blank" // @off 没必要限制 'react/jsx-no-target-blank': 'off', // 禁止使用未定义的 jsx elemet 'react/jsx-no-undef': 'error', // 禁止使用 pascal 写法的 jsx，比如 <TEST_COMPONENT> 'react/jsx-pascal-case': 'error', // @fixable props 必须排好序 // @off 没必要限制 'react/jsx-sort-props': 'off', // @fixable jsx 的开始和闭合处禁止有空格 'react/jsx-tag-spacing': [ 'error', { closingSlash: 'never', beforeSelfClosing: 'always', afterOpening: 'never' } ], // jsx 文件必须 import React 'react/jsx-uses-react': 'error', // 定义了的 jsx element 必须使用 'react/jsx-uses-vars': 'error', // @fixable 多行的 jsx 必须有括号包起来 // @off 没必要限制 'react/jsx-wrap-multilines': 'off' } };ESLint 标准规则/** * AlloyTeam ESLint 规则 * * 包含所有 ESLint 规则 * 使用 babel-eslint 作为解析器 * * @fixable 表示此配置支持 --fix * @off 表示此配置被关闭了，并且后面说明了关闭的原因 */ module.exports = { parser: 'babel-eslint', parserOptions: { ecmaVersion: 2017, sourceType: 'module', ecmaFeatures: { // @TODO Deprecated https://eslint.org/docs/user-guide/configuring#deprecated experimentalObjectRestSpread: true, jsx: true, modules: true } }, env: { browser: true, node: true, commonjs: true, es6: true }, // 以当前目录为根目录，不再向上查找 .eslintrc.js root: true, rules: { // // // 可能的错误 // 这些规则与 JavaScript 代码中可能的语法错误或逻辑错误有关 // // 禁止 for 循环出现方向错误的循环，比如 for (i = 0; i < 10; i--) 'for-direction': 'error', // getter 必须有返回值，并且禁止返回空，比如 return; 'getter-return': [ 'error', { allowImplicit: false } ], // 禁止将 await 写在循环里，因为这样就无法同时发送多个异步请求了 // @off 要求太严格了，有时需要在循环中写 await 'no-await-in-loop': 'off', // 禁止与负零进行比较 'no-compare-neg-zero': 'error', // 禁止在测试表达式中使用赋值语句，除非这个赋值语句被括号包起来了 'no-cond-assign': [ 'error', 'except-parens' ], // 禁止使用 console // @off console 的使用很常见 'no-console': 'off', // 禁止将常量作为分支条件判断中的测试表达式，但允许作为循环条件判断中的测试表达式 'no-constant-condition': [ 'error', { checkLoops: false } ], // 禁止在正则表达式中出现 Ctrl 键的 ASCII 表示，即禁止使用 /\x1f/ // @off 几乎不会遇到这种场景 'no-control-regex': 'off', // @fixable 禁止使用 debugger 'no-debugger': 'error', // 禁止在函数参数中出现重复名称的参数 'no-dupe-args': 'error', // 禁止在对象字面量中出现重复名称的键名 'no-dupe-keys': 'error', // 禁止在 switch 语句中出现重复测试表达式的 case 'no-duplicate-case': 'error', // 禁止出现空代码块，允许 catch 为空代码块 'no-empty': [ 'error', { allowEmptyCatch: true } ], // 禁止在正则表达式中使用空的字符集 [] 'no-empty-character-class': 'error', // 禁止将 catch 的第一个参数 error 重新赋值 'no-ex-assign': 'error', // @fixable 禁止不必要的布尔类型转换，比如 !! 或 Boolean 'no-extra-boolean-cast': 'error', // @fixable 禁止函数表达式中出现多余的括号，比如 let foo = (function () { return 1 }) 'no-extra-parens': [ 'error', 'functions' ], // @fixable 禁止出现多余的分号 'no-extra-semi': 'error', // 禁止将一个函数声明重新赋值，如： // function foo() {} // foo = bar 'no-func-assign': 'error', // 禁止在 if 代码块内出现函数声明 'no-inner-declarations': [ 'error', 'both' ], // 禁止在 RegExp 构造函数中出现非法的正则表达式 'no-invalid-regexp': 'error', // 禁止使用特殊空白符（比如全角空格），除非是出现在字符串、正则表达式或模版字符串中 'no-irregular-whitespace': [ 'error', { skipStrings: true, skipComments: false, skipRegExps: true, skipTemplates: true } ], // 禁止将 Math, JSON 或 Reflect 直接作为函数调用 'no-obj-calls': 'error', // 禁止使用 hasOwnProperty, isPrototypeOf 或 propertyIsEnumerable // @off hasOwnProperty 比较常用 'no-prototype-builtins': 'off', // @fixable 禁止在正则表达式中出现连续的空格，必须使用 /foo {3}bar/ 代替 'no-regex-spaces': 'error', // 禁止在数组中出现连续的逗号，如 let foo = [,,] 'no-sparse-arrays': 'error', // 禁止在普通字符串中出现模版字符串里的变量形式，如 'Hello ${name}!' 'no-template-curly-in-string': 'error', // 禁止出现难以理解的多行表达式，如： // let foo = bar // [1, 2, 3].forEach(baz); 'no-unexpected-multiline': 'error', // 禁止在 return, throw, break 或 continue 之后还有代码 'no-unreachable': 'error', // 禁止在 finally 中出现 return, throw, break 或 continue 'no-unsafe-finally': 'error', // @fixable 禁止在 in 或 instanceof 操作符的左侧使用感叹号，如 if (!key in object) 'no-unsafe-negation': 'error', // 必须使用 isNaN(foo) 而不是 foo === NaN 'use-isnan': 'error', // 注释必须符合 jsdoc 的规范 // @off jsdoc 要求太严格 'valid-jsdoc': 'off', // typeof 表达式比较的对象必须是 'undefined', 'object', 'boolean', 'number', 'string', 'function' 或 'symbol' 'valid-typeof': 'error', // // // 最佳实践 // 这些规则通过一些最佳实践帮助你避免问题 // // setter 必须有对应的 getter，getter 可以没有对应的 setter 'accessor-pairs': [ 'error', { setWithoutGet: true, getWithoutSet: false } ], // 数组的方法除了 forEach 之外，回调函数必须有返回值 'array-callback-return': 'error', // 将 var 定义的变量视为块作用域，禁止在块外使用 'block-scoped-var': 'error', // 在类的非静态方法中，必须存在对 this 的引用 // @off 太严格了 'class-methods-use-this': 'off', // 禁止函数的循环复杂度超过 20，https://en.wikipedia.org/wiki/Cyclomatic_complexity 'complexity': [ 'error', { max: 20 } ], // 禁止函数在不同分支返回不同类型的值 // @off 太严格了 'consistent-return': 'off', // @fixable if 后面必须要有 {，除非是单行 if 'curly': [ 'error', 'multi-line', 'consistent' ], // switch 语句必须有 default // @off 太严格了 'default-case': 'off', // @fixable 链式调用的时候，点号必须放在第二行开头处，禁止放在第一行结尾处 'dot-location': [ 'error', 'property' ], // @fixable 禁止出现 foo['bar']，必须写成 foo.bar // @off 当需要写一系列属性的时候，可以更统一 'dot-notation': 'off', // @fixable 必须使用 === 或 !==，禁止使用 == 或 !=，与 null 比较时除外 'eqeqeq': [ 'error', 'always', { null: 'ignore' } ], // for in 内部必须有 hasOwnProperty 'guard-for-in': 'error', // 禁止使用 alert // @off alert 很常用 'no-alert': 'off', // 禁止使用 caller 或 callee 'no-caller': 'error', // switch 的 case 内有变量定义的时候，必须使用大括号将 case 内变成一个代码块 'no-case-declarations': 'error', // 禁止在正则表达式中出现形似除法操作符的开头，如 let a = /=foo/ // @off 有代码高亮的话，在阅读这种代码时，也完全不会产生歧义或理解上的困难 'no-div-regex': 'off', // @fixable 禁止在 else 内使用 return，必须改为提前结束 // @off else 中使用 return 可以使代码结构更清晰 'no-else-return': 'off', // 不允许有空函数，除非是将一个空函数设置为某个项的默认值 'no-empty-function': [ 'error', { allow: [ 'functions', 'arrowFunctions' ] } ], // 禁止解构中出现空 {} 或 [] 'no-empty-pattern': 'error', // 禁止使用 foo == null 或 foo != null，必须使用 foo === null 或 foo !== null // @off foo == null 用于判断 foo 不是 undefined 并且不是 null，比较常用，故允许此写法 'no-eq-null': 'off', // 禁止使用 eval 'no-eval': 'error', // 禁止修改原生对象 'no-extend-native': 'error', // @fixable 禁止出现没必要的 bind 'no-extra-bind': 'error', // @fixable 禁止出现没必要的 label 'no-extra-label': 'error', // switch 的 case 内必须有 break, return 或 throw 'no-fallthrough': 'error', // @fixable 表示小数时，禁止省略 0，比如 .5 'no-floating-decimal': 'error', // 禁止对全局变量赋值 'no-global-assign': 'error', // @fixable 禁止使用 !! ~ 等难以理解的运算符 // 仅允许使用 !! 'no-implicit-coercion': [ 'error', { allow: [ '!!' ] } ], // 禁止在全局作用域下定义变量或申明函数 'no-implicit-globals': 'error', // 禁止在 setTimeout 或 setInterval 中传入字符串，如 setTimeout('alert("Hi!")', 100); 'no-implied-eval': 'error', // 禁止在类之外的地方使用 this // @off this 的使用很灵活，事件回调中可以表示当前元素，函数也可以先用 this，等以后被调用的时候再 call 'no-invalid-this': 'off', // 禁止使用 __iterator__ 'no-iterator': 'error', // 禁止使用 label 'no-labels': 'error', // 禁止使用没必要的 {} 作为代码块 'no-lone-blocks': 'error', // 禁止在循环内的函数中出现循环体条件语句中定义的变量，比如： // for (var i = 0; i < 10; i++) { // (function () { return i })(); // } 'no-loop-func': 'error', // 禁止使用 magic numbers // @off 太严格了 'no-magic-numbers': 'off', // @fixable 禁止出现连续的多个空格，除非是注释前，或对齐对象的属性、变量定义、import 等 'no-multi-spaces': [ 'error', { ignoreEOLComments: true, exceptions: { Property: true, BinaryExpression: false, VariableDeclarator: true, ImportDeclaration: true } } ], // 禁止使用 \ 来换行字符串 'no-multi-str': 'error', // 禁止直接 new 一个类而不赋值 'no-new': 'error', // 禁止使用 new Function，比如 let x = new Function("a", "b", "return a + b"); 'no-new-func': 'error', // 禁止使用 new 来生成 String, Number 或 Boolean 'no-new-wrappers': 'error', // 禁止使用 0 开头的数字表示八进制数 'no-octal': 'error', // 禁止使用八进制的转义符 'no-octal-escape': 'error', // 禁止对函数的参数重新赋值 'no-param-reassign': 'error', // 禁止使用 __proto__ 'no-proto': 'error', // 禁止重复定义变量 'no-redeclare': 'error', // 禁止使用指定的对象属性 // @off 它用于限制某个具体的 api 不能使用 'no-restricted-properties': 'off', // 禁止在 return 语句里赋值 'no-return-assign': [ 'error', 'always' ], // 禁止在 return 语句里使用 await 'no-return-await': 'error', // 禁止出现 location.href = 'javascript:void(0)'; 'no-script-url': 'error', // 禁止将自己赋值给自己 'no-self-assign': 'error', // 禁止将自己与自己比较 'no-self-compare': 'error', // 禁止使用逗号操作符 'no-sequences': 'error', // 禁止 throw 字面量，必须 throw 一个 Error 对象 'no-throw-literal': 'error', // 循环内必须对循环条件的变量有修改 'no-unmodified-loop-condition': 'error', // 禁止无用的表达式 'no-unused-expressions': [ 'error', { allowShortCircuit: true, allowTernary: true, allowTaggedTemplates: true } ], // @fixable 禁止出现没用的 label 'no-unused-labels': 'error', // 禁止出现没必要的 call 或 apply 'no-useless-call': 'error', // 禁止出现没必要的字符串连接 'no-useless-concat': 'error', // 禁止出现没必要的转义 // @off 转义可以使代码更易懂 'no-useless-escape': 'off', // @fixable 禁止没必要的 return // @off 没必要限制 return 'no-useless-return': 'off', // 禁止使用 void 'no-void': 'error', // 禁止注释中出现 TODO 和 FIXME // @off TODO 很常用 'no-warning-comments': 'off', // 禁止使用 with 'no-with': 'error', // Promise 的 reject 中必须传入 Error 对象，而不是字面量 'prefer-promise-reject-errors': 'error', // parseInt 必须传入第二个参数 'radix': 'error', // async 函数中必须存在 await 语句 // @off async function 中没有 await 的写法很常见，比如 koa 的示例中就有这种用法 'require-await': 'off', // var 必须在作用域的最前面 // @off var 不在最前面也是很常见的用法 'vars-on-top': 'off', // @fixable 立即执行的函数必须符合如下格式 (function () { alert('Hello') })() 'wrap-iife': [ 'error', 'inside', { functionPrototypeMethods: true } ], // @fixable 必须使用 if (foo === 5) 而不是 if (5 === foo) 'yoda': [ 'error', 'never', { onlyEquality: true } ], // // // 严格模式 // 这些规则与严格模式指令有关 // // @fixable 禁止使用 'strict'; 'strict': [ 'error', 'never' ], // // // 变量 // 这些规则与变量申明有关 // // 变量必须在定义的时候赋值 // @off 先定义后赋值很常见 'init-declarations': 'off', // 禁止 catch 的参数名与定义过的变量重复 // @off 太严格了 'no-catch-shadow': 'off', // 禁止使用 delete 'no-delete-var': 'error', // 禁止 label 名称与定义过的变量重复 'no-label-var': 'error', // 禁止使用指定的全局变量 // @off 它用于限制某个具体的变量名不能使用 'no-restricted-globals': 'off', // 禁止变量名与上层作用域内的定义过的变量重复 // @off 很多时候函数的形参和传参是同名的 'no-shadow': 'off', // 禁止使用保留字作为变量名 'no-shadow-restricted-names': 'error', // 禁止使用未定义的变量 'no-undef': [ 'error', { typeof: false } ], // @fixable 禁止将 undefined 赋值给变量 'no-undef-init': 'error', // 禁止对 undefined 重新赋值 'no-undefined': 'error', // 定义过的变量必须使用 'no-unused-vars': [ 'error', { vars: 'all', args: 'none', caughtErrors: 'none', ignoreRestSiblings: true } ], // 变量必须先定义后使用 'no-use-before-define': [ 'error', { functions: false, classes: false, variables: false } ], // // // Node.js 和 CommonJS // 这些规则与在 Node.js 中运行的代码或浏览器中使用的 CommonJS 有关 // // callback 之后必须立即 return // @off Limitations 太多了 'callback-return': 'off', // require 必须在全局作用域下 // @off 条件加载很常见 'global-require': 'off', // callback 中的 error 必须被处理 'handle-callback-err': 'error', // 禁止直接使用 Buffer 'no-buffer-constructor': 'error', // 相同类型的 require 必须放在一起 // @off 太严格了 'no-mixed-requires': 'off', // 禁止直接 new require('foo') 'no-new-require': 'error', // 禁止对 __dirname 或 __filename 使用字符串连接 'no-path-concat': 'error', // 禁止使用 process.env.NODE_ENV // @off 使用很常见 'no-process-env': 'off', // 禁止使用 process.exit(0) // @off 使用很常见 'no-process-exit': 'off', // 禁止使用指定的模块 // @off 它用于限制某个具体的模块不能使用 'no-restricted-modules': 'off', // 禁止使用 node 中的同步的方法，比如 fs.readFileSync // @off 使用很常见 'no-sync': 'off', // // // 风格问题 // 这些规则与代码风格有关，所以是非常主观的 // // @fixable 配置数组的中括号内前后的换行格式 // @off 配置项无法配制成想要的样子 'array-bracket-newline': 'off', // @fixable 数组的括号内的前后禁止有空格 'array-bracket-spacing': [ 'error', 'never' ], // @fixable 配置数组的元素之间的换行格式 // @off 允许一行包含多个元素，方便大数量的数组的书写 'array-element-newline': 'off', // @fixable 代码块如果在一行内，那么大括号内的首尾必须有空格，比如 function () { alert('Hello') } 'block-spacing': [ 'error', 'always' ], // @fixable if 与 else 的大括号风格必须一致 // @off else 代码块可能前面需要有一行注释 'brace-style': 'off', // 变量名必须是 camelcase 风格的 // @off 很多 api 或文件名都不是 camelcase 'camelcase': 'off', // @fixable 注释的首字母必须大写 // @off 没必要限制 'capitalized-comments': 'off', // @fixable 对象的最后一个属性末尾必须有逗号 // @off 没必要限制 'comma-dangle': 'off', // @fixable 逗号前禁止有空格，逗号后必须要有空格 'comma-spacing': [ 'error', { 'before': false, 'after': true } ], // @fixable 禁止在行首写逗号 'comma-style': [ 'error', 'last' ], // @fixable 用作对象的计算属性时，中括号内的首尾禁止有空格 'computed-property-spacing': [ 'error', 'never' ], // 限制 this 的别名 // @off 没必要限制 'consistent-this': 'off', // @fixable 文件最后一行必须有一个空行 // @off 没必要限制 'eol-last': 'off', // @fixable 函数名和执行它的括号之间禁止有空格 'func-call-spacing': [ 'error', 'never' ], // 函数赋值给变量的时候，函数名必须与变量名一致 'func-name-matching': [ 'error', 'always', { includeCommonJSModuleExports: false } ], // 函数必须有名字 // @off 没必要限制 'func-names': 'off', // 必须只使用函数声明或只使用函数表达式 // @off 没必要限制 'func-style': 'off', // 禁止使用指定的标识符 // @off 它用于限制某个具体的标识符不能使用 'id-blacklist': 'off', // 限制变量名长度 // @off 没必要限制变量名长度 'id-length': 'off', // 限制变量名必须匹配指定的正则表达式 // @off 没必要限制变量名 'id-match': 'off', // @fixable 一个缩进必须用四个空格替代 'indent': [ 'error', 4, { SwitchCase: 1, flatTernaryExpressions: true } ], // @fixable jsx 中的属性必须用双引号 'jsx-quotes': [ 'error', 'prefer-double' ], // @fixable 对象字面量中冒号前面禁止有空格，后面必须有空格 'key-spacing': [ 'error', { beforeColon: false, afterColon: true, mode: 'strict', } ], // @fixable 关键字前后必须有空格 'keyword-spacing': [ 'error', { before: true, after: true } ], // 单行注释必须写在上一行 // @off 没必要限制 'line-comment-position': 'off', // @fixable 限制换行符为 LF 或 CRLF // @off 没必要限制 'linebreak-style': 'off', // @fixable 注释前后必须有空行 // @off 没必要限制 'lines-around-comment': 'off', // 代码块嵌套的深度禁止超过 5 层 'max-depth': [ 'error', 5 ], // 限制一行的长度 // @off 现在编辑器已经很智能了，不需要限制一行的长度 'max-len': 'off', // 限制一个文件最多的行数 // @off 没必要限制 'max-lines': 'off', // 回调函数嵌套禁止超过 3 层，多了请用 async await 替代 'max-nested-callbacks': [ 'error', 3 ], // 函数的参数禁止超过 7 个 'max-params': [ 'error', 7 ], // 限制函数块中的语句数量 // @off 没必要限制 'max-statements': 'off', // 限制一行中的语句数量 // @off 没必要限制 'max-statements-per-line': 'off', // 三元表达式必须得换行 // @off 三元表达式可以随意使用 'multiline-ternary': 'off', // new 后面的类名必须首字母大写 'new-cap': [ 'error', { newIsCap: true, capIsNew: false, properties: true } ], // @fixable new 后面的类必须有小括号 'new-parens': 'error', // 链式调用必须换行 // @off 没必要限制 'newline-per-chained-call': 'off', // 禁止使用 Array 构造函数 'no-array-constructor': 'error', // 禁止使用位运算 // @off 位运算很常见 'no-bitwise': 'off', // 禁止使用 continue // @off continue 很常用 'no-continue': 'off', // 禁止在代码后添加内联注释 // @off 内联注释很常用 'no-inline-comments': 'off', // @fixable 禁止 else 中只有一个单独的 if // @off 单独的 if 可以把逻辑表达的更清楚 'no-lonely-if': 'off', // 禁止混用不同的操作符，比如 let foo = a && b < 0 || c > 0 || d + 1 === 0 // @off 太严格了，可以由使用者自己去判断如何混用操作符 'no-mixed-operators': 'off', // 禁止混用空格和缩进 'no-mixed-spaces-and-tabs': 'error', // 禁止连续赋值，比如 a = b = c = 5 // @off 没必要限制 'no-multi-assign': 'off', // @fixable 禁止出现超过三行的连续空行 'no-multiple-empty-lines': [ 'error', { max: 3, maxEOF: 1, maxBOF: 1 } ], // 禁止 if 里面有否定的表达式，比如： // if (a !== b) { // doSomething(); // } else { // doSomethingElse(); // } // @off 否定的表达式可以把逻辑表达的更清楚 'no-negated-condition': 'off', // 禁止使用嵌套的三元表达式，比如 a ? b : c ? d : e // @off 没必要限制 'no-nested-ternary': 'off', // 禁止直接 new Object 'no-new-object': 'error', // 禁止使用 ++ 或 -- // @off 没必要限制 'no-plusplus': 'off', // 禁止使用特定的语法 // @off 它用于限制某个具体的语法不能使用 'no-restricted-syntax': 'off', // 禁止使用 tabs 'no-tabs': 'error', // 禁止使用三元表达式 // @off 三元表达式很常用 'no-ternary': 'off', // @fixable 禁止行尾有空格 'no-trailing-spaces': 'error', // 禁止变量名出现下划线 // @off 下划线在变量名中很常用 'no-underscore-dangle': 'off', // @fixable 必须使用 !a 替代 a ? false : true // @off 后者表达的更清晰 'no-unneeded-ternary': 'off', // @fixable 禁止属性前有空格，比如 foo. bar() 'no-whitespace-before-property': 'error', // @fixable 禁止 if 后面不加大括号而写两行代码 'nonblock-statement-body-position': [ 'error', 'beside', { overrides: { while: 'below' } } ], // @fixable 大括号内的首尾必须有换行 'object-curly-newline': [ 'error', { multiline: true, consistent: true } ], // @fixable 对象字面量只有一行时，大括号内的首尾必须有空格 'object-curly-spacing': [ 'error', 'always', { arraysInObjects: true, objectsInObjects: false } ], // @fixable 对象字面量内的属性每行必须只有一个 // @off 没必要限制 'object-property-newline': 'off', // 禁止变量申明时用逗号一次申明多个 'one-var': [ 'error', 'never' ], // @fixable 变量申明必须每行一个 'one-var-declaration-per-line': [ 'error', 'always' ], // @fixable 必须使用 x = x + y 而不是 x += y // @off 没必要限制 'operator-assignment': 'off', // @fixable 需要换行的时候，操作符必须放在行末，比如： // let foo = 1 + // 2 // @off 有时放在第二行开始处更易读 'operator-linebreak': 'off', // @fixable 代码块首尾必须要空行 // @off 没必要限制 'padded-blocks': 'off', // @fixable 限制语句之间的空行规则，比如变量定义完之后必须要空行 // @off 没必要限制 'padding-line-between-statements': 'off', // @fixable 对象字面量的键名禁止用引号括起来 // @off 没必要限制 'quote-props': 'off', // @fixable 必须使用单引号，禁止使用双引号 'quotes': [ 'error', 'single', { avoidEscape: true, allowTemplateLiterals: true } ], // 必须使用 jsdoc 风格的注释 // @off 太严格了 'require-jsdoc': 'off', // @fixable 结尾必须有分号 'semi': [ 'error', 'always', { omitLastInOneLineBlock: true } ], // @fixable 一行有多个语句时，分号前面禁止有空格，分号后面必须有空格 'semi-spacing': [ 'error', { before: false, after: true } ], // @fixable 分号必须写在行尾，禁止在行首出现 'semi-style': [ 'error', 'last' ], // 对象字面量的键名必须排好序 // @off 没必要限制 'sort-keys': 'off', // 变量申明必须排好序 // @off 没必要限制 'sort-vars': 'off', // @fixable if, function 等的大括号之前必须要有空格，比如 if (a) { 'space-before-blocks': [ 'error', 'always' ], // @fixable function 的小括号之前必须要有空格 'space-before-function-paren': [ 'error', { anonymous: 'ignore', named: 'never', asyncArrow: 'always' } ], // @fixable 小括号内的首尾禁止有空格 'space-in-parens': [ 'error', 'never' ], // @fixable 操作符左右必须有空格，比如 let sum = 1 + 2; 'space-infix-ops': 'error', // @fixable new, typeof 等后面必须有空格，++, -- 等禁止有空格，比如： // let foo = new Person(); // bar = bar++; 'space-unary-ops': [ 'error', { words: true, nonwords: false } ], // @fixable 注释的斜线或 * 后必须有空格 'spaced-comment': [ 'error', 'always', { block: { exceptions: [ '*' ], balanced: true } } ], // @fixable case 的冒号前禁止有空格，冒号后必须有空格 'switch-colon-spacing': [ 'error', { after: true, before: false } ], // @fixable 模版字符串的 tag 之后禁止有空格，比如 tag`Hello World` 'template-tag-spacing': [ 'error', 'never' ], // @fixable 文件开头禁止有 BOM 'unicode-bom': [ 'error', 'never' ], // @fixable 正则表达式必须有括号包起来 // @off 没必要限制 'wrap-regex': 'off', // // // ECMAScript 6 // 这些规则与 ES6（即通常所说的 ES2015）有关 // // @fixable 箭头函数能够省略 return 的时候，必须省略，比如必须写成 () => 0，禁止写成 () => { return 0 } // @off 箭头函数的返回值，应该允许灵活设置 'arrow-body-style': 'off', // @fixable 箭头函数只有一个参数的时候，必须加括号 // @off 应该允许灵活设置 'arrow-parens': 'off', // @fixable 箭头函数的箭头前后必须有空格 'arrow-spacing': [ 'error', { before: true, after: true } ], // constructor 中必须有 super 'constructor-super': 'error', // @fixable generator 的 * 前面禁止有空格，后面必须有空格 'generator-star-spacing': [ 'error', { before: false, after: true } ], // 禁止对定义过的 class 重新赋值 'no-class-assign': 'error', // @fixable 禁止出现难以理解的箭头函数，比如 let x = a => 1 ? 2 : 3 'no-confusing-arrow': [ 'error', { allowParens: true } ], // 禁止对使用 const 定义的常量重新赋值 'no-const-assign': 'error', // 禁止重复定义类 'no-dupe-class-members': 'error', // 禁止重复 import 模块 'no-duplicate-imports': 'error', // 禁止使用 new 来生成 Symbol 'no-new-symbol': 'error', // 禁止 import 指定的模块 // @off 它用于限制某个具体的模块不能使用 'no-restricted-imports': 'off', // 禁止在 super 被调用之前使用 this 或 super 'no-this-before-super': 'error', // @fixable 禁止出现没必要的计算键名，比如 let a = { ['0']: 0 }; 'no-useless-computed-key': 'error', // 禁止出现没必要的 constructor，比如 constructor(value) { super(value) } 'no-useless-constructor': 'error', // @fixable 禁止解构时出现同样名字的的重命名，比如 let { foo: foo } = bar; 'no-useless-rename': 'error', // @fixable 禁止使用 var 'no-var': 'error', // @fixable 必须使用 a = {b} 而不是 a = {b: b} // @off 没必要强制要求 'object-shorthand': 'off', // @fixable 必须使用箭头函数作为回调 // @off 没必要强制要求 'prefer-arrow-callback': 'off', // @fixable 申明后不再被修改的变量必须使用 const 来申明 // @off 没必要强制要求 'prefer-const': 'off', // 必须使用解构 // @off 没必要强制要求 'prefer-destructuring': 'off', // @fixable 必须使用 0b11111011 而不是 parseInt('111110111', 2) // @off 没必要强制要求 'prefer-numeric-literals': 'off', // 必须使用 ...args 而不是 arguments // @off 没必要强制要求 'prefer-rest-params': 'off', // @fixable 必须使用 ... 而不是 apply，比如 foo(...args) // @off apply 很常用 'prefer-spread': 'off', // @fixable 必须使用模版字符串而不是字符串连接 // @off 字符串连接很常用 'prefer-template': 'off', // generator 函数内必须有 yield 'require-yield': 'error', // @fixable ... 的后面禁止有空格 'rest-spread-spacing': [ 'error', 'never' ], // @fixable import 必须按规则排序 // @off 没必要强制要求 'sort-imports': 'off', // 创建 Symbol 时必须传入参数 'symbol-description': 'error', // @fixable ${name} 内的首尾禁止有空格 'template-curly-spacing': [ 'error', 'never' ], // @fixable yield* 后面必须要有空格 'yield-star-spacing': [ 'error', 'after' ] } };常见问题取消eslint的变量未使用报错问题在tsconfig.json文件里设置这两个变量为false"noUnusedLocals": false, "noUnusedParameters": false,在.eslintrc.js文件里设置："no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "off"
网易云音乐、bilibili、微信、支付宝运动步数-云任务助手
[scode type="green"] ::aru:proud:: 助手介绍[/scode]网上很多代挂助手挺好玩的，但是又觉得用别人的不习惯，那只能为理想买单啦，于是花了一周的饭钱188 买了oneTool助手的授权自己搭建了一下，虽然api还使用的别人的 但是最起码有了心理安慰 文章最后有惊喜登录地址：http://test.97dk.top开箱即用、不用付费直接白嫖还不快冲！vip卡密每人限1个哈,有肉大家一起吃！[scode type="green"] ::aru:frown:: 功能介绍[/scode][tabs][tab name="网易云音乐" active="true"]功能：每日签到，每日云贝，打卡300首歌，音乐人任务-可以领取一年黑胶会员[/tab][tab name="哔哩哔哩"]功能：每日礼包，每日观看，每日分享，漫画任务等等各种功能[/tab][tab name="运动步数"]功能：微信运动、支付宝运动、可以指定部署范围（不用登录微信或者支付宝）[/tab][tab name="爱奇艺"]功能：每日签到，每日三抽，积分任务、VIP日常任务、VIP其他任务[/tab][tab name="QQ空间"]功能：自动点赞，自动发说说，自动评论，腾讯视频自动签到[/tab][/tabs][scode type="blue"] ::aru:shy2:: 免费卡密[/scode]
1.为什么使用图片懒加载？为了解决 一进入页面，所有的图片都会一次性加载，这可能会造成网络资源和降低用户的体验。比如某宝App打开之后会加载很多商品预览图片,每个图片都是一个请求,那么刚进入页面就发很多请求会造成性能的浪费，从用户的角度来看会给用户一种卡顿的感觉极其影响购物体验所以使用 图片懒加载，只有当用户滚动页面，真正的浏览的到这些列表项 ，才开始加载那些图片2.原理3.原生Api代码实现[scode type="green"]Intersection ObserverMDN官方文档[/scode]利用浏览器提供的 intersectionObserverApi,监听图片元素是否进入到可视区域，进入之后才真正的去设置图片元素的 src属性进行图片加载。还额外针对图片加载是否出错做了处理。如果图片加载出错，显示约定好的图片。图片不直接设置src，通过data-src属性设置图片地址,直接设置一进页面就会加载当图片进入可视区后在进行加载通过IntersectionObserver监听进入可视区域如果进入可视区域后将data-src中存储的地址赋值给src原生demo： </bodyReact封装组件：type Props = { src: string className?: string } /** * 拥有懒加载特性的图片组件 * @param {String} props.src 图片地址 * @param {String} props.className 样式类 */ const Image = ({ src, className }: Props) => { // 记录图片加载是否出错的状态 const [isError, setIsError] = useState(false) // 记录图片是否正在加载的状态 const [isLoading, setIsLoading] = useState(true) // 对图片元素的引用 类型设置 const imgRef = useRef<HTMLImageElement | null>(null) // 组件收到src后 先储存起来 // 建立监听 useEffect(() => { const io = new IntersectionObserver(([{ isIntersecting, target }]) => { // 如果isIntersecting = true 代表进入了可视区域 if (isIntersecting) { // 获取Dom元素 ! 非空断言 const imgDom = imgRef.current! // 进入之后将data-src的值赋值给src imgDom.src = imgDom.dataset.src! // 设置之后结束特定监听 io.unobserve(imgDom) } //组件卸载时 触发全部停止监听 return () => { io.disconnect() } }) // 开启监听 io.observe(imgRef.current!) }) return ( {/* 正在加载时显示的内容 */} {isLoading && ( <Icon type="iconphoto" /> )} {/* 加载出错时显示的内容 */} {isError && ( <Icon type="iconphoto-fail" /> )} {/* 加载成功时显示的内容 */} {!isError && ( setIsLoading(false)} onError={() => setIsError(true)} /> )} ) }
简述TCP三次握手和四次挥手面试回答
简述TCP三次握手和四次挥手面试回答[scode type="green"]本文转自 猿人谷 长期维护版本：https://yuanrengu.com/2020/77eef79f.html[/scode][scode type="lblue"]目前把下面总结好的理解并且牢记完全可以应对面试官。[/scode]三次握手四次挥手是前端常见面试题之一，也被一些面试官作为热身题。很多小伙伴说这个问题刚开始回答的挺好，但是后面越回答越冒冷汗，最后就歇菜了。希望大家带着如下问题进行阅读，收获会更大。1.请说出三次握手的作用以及过程2.ISN(Initial Sequence Number)是固定的吗？3.三次握手过程中可以携带数据吗？4.什么是半连接队列？5.三次握手可以携带参数吗？6.四次挥手的过程首先看一张图来理解一下整个三次握手过程一、三次握手1.三次握手的作用作用：确定双方的接收、发送能力是否正常，指定自己的初始化序列号，为后续可靠传输做准备1.2 三次握手的过程刚开客户端处于Closed状态，服务端处于Listen状态第一次握手：客户端向服务端发送SYN报文，并指明客户端初始化序列号ISN(c),此时客户端进入SYN_send状态/等待第二次握手：服务端收到SYN报文后，会以自己的SYN作为应答，并指明自己的初始化序列号ISN，同时将客户端的ISN+1作为Ack的值，表示收到客户端的SYN，同时进入SYN_RCVD状态/接收第三次：客户端收到SYN后，发送一个ACK报文，也是将服务端的ISN+1作为ACK的值，表示收到服务端的SYN报文。此时客户端处于established状态，服务端收到ACK后，也处于established状态，此时双方成功建立连接2.ISN是固定的吗？答案：不是固定的，三次握手的一个重要功能就是交换双方的ISN，以便让对方知道接收到的输入如何按序列号进行组装，如果ISN是固定的，攻击者很容易推断出后续的确认号，所以ISN是动态生成的3.什么是半连接队列？服务端第一次收到SYN后，就会处于SYN_RCVD,此时双方还没完全建立连接，服务端会把这种状态放在一个队列中，我们把这这种队列称为半连接队列，等三次握手完毕后，建立的连接就会放在全连接队列中，如果队列满了就会产生丢包的情况。4.三次握手可以携带参数吗？第三次握手时可以携带参数，第一次和第二次不能携带，举例：第一次就可以携带参数的话，假如有人恶意攻击服务器，攻击者根本不在乎服务器的接收、发送能力是否正常，如果每次都在第一次握手中的SYN报文中携带大量数据，重复的发SYN报文的话，那么服务器会花费大量时间、内存空间接收这些报文。所以得出的结论，如果在第一次握手中携带数据，那么服务器更容易收到攻击对于在第三次携带数据的话，此时客户端已经处于established状态，对于客户端来说已经建立连接，并且确定服务端的发送和接收能力时正常的，所以携带参数完全没问题。二、四次挥手第一次挥手：客户端发送一个FIN报文，报文中指定一个序列号，此时客户端进入FIN_WAIT_1状态，表示停止在发送数据第二次挥手：服务端收到FIN报文后，会回应一个ACK报文，把客户端的序列号+1作为ACK的值，此时服务端处于Close_WAIT状态，表示服务端同意关闭请求，客户端进入FIN_WAIT2状态 等待服务端发出连接释放报文第三次挥手：如果服务端也想断开连接了，和第一次挥手一样发出FIN报文，此时服务端处于LAST_ACK状态，表示发出连接释放报文，等待客户端确认第四次挥手：客户端收到FIN报文后，一样发送一个ACK报文，且把服务器的序列号+1作为ACK的值。此时客户端进入TIME_WAIT状态，需要经过等待计时器的时间2MSL后仍然没有回复，才会进入closed状态，而服务端收到ACK报文后直接进入Closed状态
一、移动web部分1、前端页面有哪三层构成，分别是什么？作用是什么？1、结构层：由 HTML 标记语言负责创建，仅负责语义的表达。解决了页面“内容是什么”的问题。 2、表示层：由CSS负责创建，解决了页面“如何显示内容”的问题。 3、行为层：由脚本（js）负责。解决了页面上“内容应该如何对事件作出反应”的问题2、主流的浏览器分别是什么内核？Trident内核：（国产的绝大部分浏览器）IE，360，搜狗 Gecko内核：Firefox，NetScape6及以上 Presto内核：Opera7及以上 Webkit内核：（国产大部分双核浏览器其中一核）Safari（苹果），Chrome3、如何居中一个浮动元素?父元素和子元素同时左浮动，然后父元素相对左移动50%，再然后子元素相对右移动50%，或者子元素相对左移动-50%也就可以了。 Test Float Element Center 4、行内元素有哪些？块级元素有哪些？空元素（void）有哪些？1、行内元素：a，b，span，img，input，strong，label，button，select，textarea，em 2、块级元素：div，ul（无序列表），ol，li，dl（自定义列表），dt（自定义列表项），dd（自定义列表项的定义），p，h1-h6，blockquote（块引用） 3、空元素（void）：即没有内容的HTML元素。br（换行），hr（水平分割线），meta，link，input，img5、BFC（Block Formatting Context，块级格式化上下文）1、是什么：决定了元素如何对其内容进行定位，以及与其他元素的关系和相互作用。简言之，就是一个特殊的块，内部的元素和外部的元素不会相互影响。BFC内的盒子会在垂直方向上一个接一个地放置，垂直方向上也会发生外边距重叠。 2、应用场景：自适应布局（BFC不与float box重叠）、清除浮动（计算BFC的高度时，内部的浮动元素也被计算在内）、防止外边距重叠 3、如何触发BFC：float属性（不为none）、overflow属性（不为visible）、position属性（absolute，fixed）、display属性（inline-block，table-cell，table-caption，flex，inline-flex）6、CSS选择器的优先级!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 7、初始化CSS样式的意义1、为什么要初始化CSS样式：因为浏览器的兼容问题，不同浏览器对有些标签的默认值是不同的，如果没有对CSS初始化往往会出现浏览器之间的页面显示差异。8、HTML5新增了哪些属性1. 语义化标签: header nav section article aside footer 2. 多媒体标签: video audio 3. input类型: number search email tel date file time url 4. 本地离线存储 localStorage 长期存储数据,改变浏览器数据不会丢失 sessionStorage 浏览器关闭数据会丢失 5. 自定义属性 data-* 6. 画布 Canvas 7. webscoket 双向通信协议9、CSS3新增了哪些属性1. 圆角 border-radius 2. 盒子模型 box-sizing 3. 阴影 box-shadow 盒子阴影 text-shadow 文字阴影 4. 过渡 transition 5. 2D转换transform translate(平移) scale(缩放) skew(斜切) rotate(旋转) transform-origin 控制转换中心点 6. 3D转换 perspective(透视距) transform-style(3D控件效果) 7. 渐变 linear-gradient radial-gradient 8. 弹性布局 flex 9. 媒体查询 @media screen and () {...} 10. 边框图片 border-image 11. 自定义动画 @keyframes animation 12. 颜色 新增RGBA HSLA模式 13. 背景 background-size background-origin background-clip10、对HTML语义化的理解1、用正确的标签做正确的事情 2、HTML语义化让页面的内容结构化，结构更清晰，便于对浏览器、搜索引擎解析 3、即使在没有样式CSS情况下也以一种文档格式显示，并且是易于阅读的 4、搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重，利于SEO 5、使阅读源代码的人更容易将网站分块，便于阅读维护理解11、CSS的盒子模型1、有两种， IE 盒子模型、W3C 盒子模型； 2、盒模型： 内容(content)、填充(padding)、边界(margin)、 边框(border)； 3、区 别： IE的content部分把 border 和 padding计算了进去;11.1、css写一个三角形答: div { width: 0; height: 0; border: 20px solid transparent; border-width: 40px 20px 0 0; border-right-color: #f99; }12、如何居中div1、 水平居中：给div设置一个宽度，然后添加margin:0 auto属性 div{ width:200px; margin:0 auto;} 2、让绝对定位的div居中 div { position: absolute; width: 300px; height: 300px; margin: auto; top: 0; left: 0; bottom: 0; right: 0; background-color: pink; } 3、水平垂直居中一 确定容器的宽高 宽500 高 300 的层 设置层的外边距 div { position: relative; /* 相对定位或绝对定位均可 */ width:500px; height:300px; top: 50%; left: 50%; margin: -150px 0 0 -250px; /* 外边距为自身宽高的一半 */ background-color: pink; /* 方便看效果 */ } 4、水平垂直居中二 未知容器的宽高，利用 `transform` 属性 div { position: absolute; /* 相对定位或绝对定位均可 */ width:500px; height:300px; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: pink; /* 方便看效果 */ } 5、水平垂直居中三 利用 flex 布局 实际使用时应考虑兼容性 .container { display: flex; align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中 */ } .container div { width: 100px; height: 100px; background-color: pink; /* 方便看效果 */ } 13、不定宽高的div水平垂直居中答: 1、父元素添加 position: relative div{ position:absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } 2、div { display: flex; justify-content:center; //子元素水平居中 align-items:center; //子元素垂直居中 } 3、#box { width: 100px; height: 100px; position: relative; } #content { width: 50px; height: 50px; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }14、px/em/rem有什么区别1、px 是固定的像素，一旦设置了就无法因为适应页面大小而改变 2、em 和rem相对于px更具有灵活性，他们是相对长度单位，意思是长度不是定死了的，更适用于响应式布局 3、em 相对自身font-size，没有则相对于父元素，rem相对于根元素的font-size15、rem布局的原理1、rem 是css的相对单位，rem缩放是相对根元素字体大小. 2、rem 布局的本质是等比缩放，一般是基于宽度。 3、rem 会配合媒体查询（或js动态获取屏幕宽度）来一起使用，来实现屏幕的适配。16、盒子塌陷的原因？解决方式原因: 1. 浮动导致的塌陷,浮动会脱落标准流 2. 嵌套的两个盒子,子盒子设置margin-top会导致父盒子一下下移 解决方法:第一种情况 1 清除浮动; 2 给父盒子加高度; 3 给父元素添加overflow:hidden 第二种情况 1 给父元素加上边框; 2 给父元素添加overflow:hidden17、如何设置比12px更小的字体答: p { font-size:12px; -webkit-transform:scale(0.8); }18、flex常用的容器属性答: 1. flex-direction: 设置容器中的主轴方向 2. flex-wrap: 项目在主轴方向上是否换行显示 3. justify-content: 设置容器中的项目在主轴上的对齐方式 4. align-items: 单行项目在侧轴上的排列方式 5. align-content: 多行项目侧轴上的对齐方式 6. flex-flow: 是flex-direction和flex-wrap的合写, 默认值为row nowrap二、JS基础部分1、什么是重绘和重排答: 重排: 当DOM元素影响了元素的几何属性（例如宽和高），浏览器需要重新计算元素的几何属性，同样其它元素的几何属性也会和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效，并重新构造渲染树。这个过程称为“重排”。 重绘: 完成重排后，浏览器会重新绘制受影响的部分到屏幕上中，该过程称为“重绘”。 当我们改变DOM的大小，增加删除都会导致重排，当给DOM元素改变颜色的时候，会导致重绘，重排一定会重绘，重绘不会重排。重排会影响性能，所以我们尽快能的减少重排的操作2、js的数据类型有哪些答: 简单数据类型: number string boolean undefined null 复杂数据类型: object function array3、js的运行机制是什么答：js是单线程执行的，页面加载时，会自上而下执行主线程上的同步任务，当主线程代码执行完毕时，才开始执行在任务队列中的异步任务。具体如下 1.所有同步任务都在主线程上执行，形成一个执行栈。 2.主线程之外，还存在一个"任务队列(eventloop队列或者消息队列)"。只要异步任务有了运行结果，就在"任务队列"之中放置一个事件。 3.一旦"执行栈"中的所有同步任务执行完毕，系统就会读取"任务队列"，看看里面有哪些事件。哪些对应的异步任务，于是结束等待状态，进入执行栈，开始执行。 4.主线程不断重复上面的第三步。3.1、异步函数有哪些JavaScript 中常见的异步函数有：定时器，事件和 ajax 等4、typeof返回的数据类型答: number string boolean undefined object function 特殊情况： typeof null -->object typeof array -->object typeof typeof 任何类型 -->string5、返回false的情况有哪些答: 0 "" null false NaN undefined 不成立的表达式6、对this的理解``` this是个关键字,它的指向和函数的调用方式有关 1. 函数调用模式, this指向window 2. 构造函数调用模式, this指向新创建的实例对象 3. 方法调用模式, this指向调用方法的对象 4. 上下文调用模式, call和apply方法中, this指向方法内的第一个参数 bind方法中, bind创建的新函数的this绑定为bind方法中新的函数 5. 在事件处理函数中,this指向触发事件的当前元素 6. 定时器中,this指向window 7. 箭头函数中没有this指向问题,它的this和外层作用域的this保持一致 8. 匿名函数中的this总是指向window ​````7、null和undefined的区别答：null 表示空值 没有获取到。typeof null 返回"object" undefined 表示未定义，声明没有值。typeof undefined 返回"undefined"8、let、const、var的区别1、var声明变量存在提升（提升当前作用域最顶端），let和const是不存在变量提升的情况 2、var没有块级作用，let和const存在块级作用域 3、var允许重复声明，let和const在同一作用域不允许重复声明 4、var和let声明变量可以修改，const是常量不能改变9、==和===的区别答：== 表示是相等，只比较内容 === 表示是全等，不仅比较内容，也比较类型10、伪数组和真数组的区别伪数组： 1、拥有length属性 2、不具有数组的方法 3、伪数组是一个Object，真数组是Array 4、伪数组的长度不可变，真数组的长度是可变的11、哪些情况会得到伪数组1、参数 arguments， arguments 是一个类数组对象，里面保存着调用函数时传入的实参 2、DOM 对象列表（比如通过 document.getElementsByTags 得到的列表）、childNodes也是伪数组 3、jQuery 对象（比如 $("div")）12、本地存储localStorage、sessionStorage和cookie的区别答: 共同点: 都可以用来存储数据。 区别: 1. 请求不同: cookie 数据始终在同源的http请求中携带（即使不需要），即cookie在浏览器和服务器间来回传递。 sessionStorage 和 localStorage不会自动把数据发给服务器，仅在本地保存。 2. 存储大小限制也不同: cookie 数据不能超过4k，同时因为每次http请求都会携带cookie，所以cookie只适合保存很小的数据，如会话标识。 sessionStorage 和 localStorage虽然也有存储大小的限制，但比cookie大得多，sessionStorage和localStorage约5M 。 3. 数据有效期不同: sessionStorage：仅在当前浏览器窗口关闭前有效，自然也就不可能持久保持； localStorage：始终有效，窗口或浏览器关闭也一直保存，因此用作持久数据； cookie只在设置的cookie过期时间之前一直有效，即使窗口或浏览器关闭。 三、JS高级部分1、值类型和引用类型的区别1、值类型 1）基本类型数据是值类型 2）保存与复制的是值本身 3）使用typeof检测数据的类型 2、引用类型 1）保存与复制的是指向对象的一个指针 2）使用instanceof检测数据类型 3）使用 new() 方法构造出的对象是引用型 2、什么是深拷贝什么是浅拷贝答: 浅拷贝: 拷贝对象的一层属性,如果对象里面还有对象,拷贝的是地址, 两者之间修改会有影响,适用于对象里面属性的值是简单数据类型的. 深拷贝: 拷贝对象的多层属性,如果对象里面还有对象,会继续拷贝,使用递归去实现.3、如何实现深拷贝和浅拷贝浅拷贝: var obj = { class: 'UI', age: 20, love: 'eat' } function getObj(obj) { var newObj = {} for (var k in obj) { newObj[k] = obj[k] } return newObj } var obj2 = getObj(obj) console.log(obj2)深拷贝: var obj = { class: '前端', age: 26, love: { friuts : 'apple', meat: 'beef' } } function getObj(obj) { var newObj = {} for (var k in obj) { /* if (typeof obj[k] == 'object') { newObj[k] = getObj(obj[k]) } else { newObj[k] = obj[k] } */ newObj[k] = typeof obj[k] == 'object' ? getObj(obj[k]) : obj[k] } return newObj } var obj2 = getObj(obj) console.log(obj2)4、什么是原型和原型链答: 原型: 函数都有prototype属性,这个属性的值是个对象,称之为原型 原型链: 对象都有__proto__属性,这个属性指向它的原型对象,原型对象也是对象,也有__proto__属性,指向原型对象的原型对象,这样一层一层形成的链式结构称为原型链.5、call、apply和bind的区别答: 14、call、apply和bind的区别 ​``` 答: 1. call和apply方法都可以调用函数,方法内的第一个参数可以修改this的指向 2. call方法可以有多个参数,除了第一个参数,其他参数作为实参传递给函数 apply方法最多有2个参数,第二个参数是个数组或伪数组,数组里面的每一项作为实参传递给函数 3. bind方法不能调用函数,它会创建一个副本函数,并且绑定新函数的this指向bind返回的新的函数 ​```6、怎么理解面向对象答：1、面向对象是一种软件开发的思想和面向过程是相对应的，就是把程序看作一个对象，将属性和方法封装其中，以提高代码的灵活性、复用性、可扩展性。 2、面向对象有三大特性：封装、继承、多态。 封装：把相关的信息（无论数据或方法）存储在对象中的能力 继承：由另一个类（或多个类）得来类的属性和方法的能力 多态：编写能以多种方法运行的函数或方法的能力 3、基本思想是使用对象，类，继承，封装等基本概念来进行程序设计 易维护 易扩展 开发工作的重用性、继承性高，降低重复工作量。 缩短了开发周期 4、js中对象是一个无序的数据集合或者也可以说是属性和方法的集合，可以动态的添加属性可方法。 5、js是基于对象，但是也使用了嵌入了面向对象的思想，可以实现继承和封装，这样也可以提供代码的灵活性和复用性。7、数组如何进行降维（扁平化）1、利用Array.some方法判断数组中是否还存在数组，es6展开运算符连接数组 let arr = [1,2,[3,4]] while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } 2、使用数组的concat方法 let arr = [1,2,[3,4]] let result = [] result = Array.prototype.concat.apply([], arr) 3、 使用数组的concat方法和扩展运算符 var arr = [1,2,[3,4]] var result = [] result = [].concat(...arr) 4、es6中的flat函数也可以实现数组的扁平化 let arr = [1,2,['a','b',['中','文',[1,2,3,[11,21,31]]]],3]; let result = arr.flat( Infinity ) 注意：flat方法的infinity属性，可以实现多层数组的降维8、对闭包的理解？并能举出闭包的例子答: 闭包 函数和声明该函数的词法环境的组合(两个嵌套关系的函数,内部函数可以访问外部函数定义的变量) 闭包的优点：1、形成私有空间，避免全局变量的污染 2、持久化内存，保存数据 闭包的缺点：1、持久化内存，导致内存泄露 解决：1、尽快避免函数的嵌套，以及变量的引用 2、执行完的变量，可以赋值null，让垃圾回收机制，进行回收释放内存（当不在引用的变量，垃圾回收机制就会回收）例: 点击li获取当前下标 111 222 333 444 555 var lis = document.querySelectorAll('li') for (var i = 0; i < lis.length; i++) { (function (j) { lis[j].onclick = function () { console.log(j) } })(i) }9、es6-es10新增常用方法答: es6: 1、let、const 2、解构赋值 let { a, b } = { a: 1, b: 2 } 3、箭头函数 ()=>{} 4、字符串模板 `` 5、扩展运算符 ...arr 6、数组方法：map、filter、some等等 7、类：class关键字 8、promise 主要用于异步计算 9、函数参数默认值 fn(a = 1) {} 10、对象属性简写 let a = 1; let obj = {a} 11、模块化：import--引入、exprot default--导出 es7: 1、includes()方法，用来判断一个数组是否包含一个指定的值，根据情况，如果包含则返回true，否则返回false。 es8: 1、async/await es9： 1、Promise.finally() 允许你指定最终的逻辑 es10: 1、数组Array的flat()和flatmap() flat:方法最基本的作用就是数组降维 var arr1 = [1, 2, [3, 4]]; arr1.flat(); // [1, 2, 3, 4] var arr3 = [1, 2, [3, 4, [5, 6]]]; arr3.flat(2); // [1, 2, 3, 4, 5, 6] //使用 Infinity 作为深度，展开任意深度的嵌套数组 arr3.flat(Infinity); // [1, 2, 3, 4, 5, 6] flatmap:方法首先使用映射函数映射(遍历)每个元素，然后将结果压缩成一个新数组四、Ajax部分1、原生注册事件的方式？区别是什么答: 注册方式 1. on + 事件名称 2. addEventListener 区别: 1. 使用on注册事件,同一个元素只能注册一个同类型事件,否则会覆盖。 2. addEventListener可以注册同一事件多次,不会被覆盖。2、http和https的区别答: 1.https协议需要到CA申请证书，一般免费证书较少，因而需要一定费用。 2.http是超文本传输协议，信息是明文传输，https则是具有安全性的ssl/tls加密传输协议。 3.http和https使用的是完全不同的连接方式，用的端口也不一样，前者是80，后者是443。 4.http的连接很简单，是无状态的；HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议，比http协议安全。3、get 和post的区别答: get 1. 在url后面拼接参数,只能以文本的形式传递数据 2. 传递的数据量小,4KB左右 3. 安全性低, 会将数据显示在地址栏 4. 速度快,通常用于安全性要求不高的请求 5. 会缓存数据 post 1. 安全性比较高 2. 传递数据量大,请求对数据长度没有要求 3. 请求不会被缓存,也不会保留在浏览器历史记录里4、原生 ajax 请求的步骤答：1.创建异步对象 var xhr = new HTMLHttpRequest() 2.设置请求行 xhr.open() 3.设置请求头 xhr.setRequestHeader() get请求没有请求头 4.设置请求体 xhr.send 5.设置监听事件 addEventListener('load',function)5、项目中常遇到的状态码有哪些答: 200 请求成功, 2开头的异步表示请求成功 304 请求被允许,但请求内容没有改变, 3开头的一般请求完成 400 请求格式错误, 4开头的一般表示请求错误 404 请求的资源(网页)不存在, 500 内部服务器错误, 5开头的一般都是指服务器错误6、什么是同源策略？怎么解决跨域问题答: 同源策略: 同源策略是浏览器的一种安全策略, 所谓同源是指域名、协议、端口完全相同，不同源则跨域。 解决跨域的方法: 1. 通过jsonp跨域 2. 跨域资源共享（CORS Access-Control-Allow-Origin: http://api.bob.com） 3. nginx代理跨域7、jsonp的原理？以及优答: 原理: 利用script标签的src属性具有天然可跨域的特性，由服务端返回一个预先定义好的Javascript函数的调用，并且将服务器数据以该函数参数的形式响应给浏览器. 优点: 完美解决在测试或者开发中获取不同域下的数据,用户传递一个callback参数给服务端，然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据，这样客户端就可以随意定制自己的函数来自动处理返回数据了。 缺点：Jsonp只支持get请求而不支持post 请求,也即是说如果想传给后台一个json 格式的数据,此时问题就来了, 浏览器会报一个http状态码41错误,告诉你请求格式不正确.8、在地址栏输入网址，到数据返回的过程是什么？答: 1. 输入url地址后，首先进行DNS解析，将相应的域名解析为IP地址。 2. 根据IP地址去寻找相应的服务器。 3. 与服务器进行TCP的三次握手，建立连接。 4. 客户端发送请求，找到相应的资源库。 5. 客户端拿到数据，进行相应的渲染。9、你对WebSocket了解哪些答: WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信，能更好的节省服务器资源和带宽并达到实时通讯，它建立在TCP之上，同HTTP一样通过TCP来传输数据，但是它和HTTP最大不同是： 1. WebSocket是一种双向通信协议，在建立连接后，WebSocket服务器和Browser/Client Agent都能主动的向对方发送或接收数据，就像Socket一样； 2. WebSocket需要类似TCP的客户端和服务器端通过握手连接连接成功后才能相互通信。10、怎么理解三次握手字段 含义 URG 紧急指针是否有效。为1，表示某一位需要被优先处理 ACK 确认号是否有效，一般置为1。 PSH 提示接收端应用程序立即从TCP缓冲区把数据读走。 RST 对方要求重新建立连接，复位。 SYN 请求建立连接，并在其序列号的字段进行序列号的初始值设定。建立连接，设置为1 FIN 希望断开连接。 1、三次握手 第一次握手：建立连接时，客户端发送syn包到服务器，等待服务器确认。 第二次握手：服务器收到syn包，必须确认客户的SYN，同时自己也发送一个SYN包（syn=y）到客户端 第三次握手：客户端收到服务器的SYN+ACK包，向服务器发送确认包ACK，此包发送完毕，客户端和服务器进入（TCP连接成功）状态，完成三次握手 （通俗：主机1告诉主机2，我可以向你请求数据吗。主机2告诉主机1，可以请求数据。主机1告诉主机2，那我来请求数据了，请求完成，实现三次握手）11、怎么理解四次挥手1、四次挥手 第一次分手：主机1（可以使客户端，也可以是服务器端）向主机2发送一个FIN报文段；此时，主机1进入FIN_WAIT_1状态；这表示主机1没有数据要发送给主机2了。 第二次分手：主机2收到了主机1发送的FIN报文段，向主机1回一个ACK报文段，主机1进入FIN_WAIT_2状态；主机2告诉主机1，我“同意”你的关闭请求。 第三次分手：主机2向主机1发送FIN报文段，请求关闭连接，同时主机2进入LAST_ACK状态。 第四次分手：主机1收到主机2发送的FIN报文段，向主机2发送ACK报文段，然后主机1进入TIME_WAIT状态；主机2收到主机1的ACK报文段以后，就关闭连接；此时，主机1等待2MSL后依然没有收到回复，则证明Server端已正常关闭，那好，主机1也可以关闭连接了。 （通俗：主机1告诉主机2，我没有数据要发送了，希望断开连接。主机2接到请求后说，同意断开。主机2告诉主机1可以关闭连接了。主机1接到可以关闭的指令后，关闭连接，四次挥手完成）12、json 与 对象和数组之间的转化json 本质上就是一个字符串, 数组或者对象的字符串表示法 序列化 对象和数组 ===> json JSON.stringify(对象或者数组) 反序列化 json ===> 对象或者数组 JSON.parse(json)13、怎么理解函数的防抖和节流答: 1、定义： 防抖: 就是指触发事件后在n秒内函数只能执行一次，如果在n秒内又触发了事件，则会重新计算函数执行时间。 例如：设定1000毫秒执行，当你触发事件了，他会1000毫秒后执行，但是在还剩500毫秒的时候你又触发了事件，那就会重新开始1000毫秒之后再执行 节流: 就是指连续触发事件但是在设定的一段时间内中只执行一次函数。 例如：设定1000毫秒执行，那你在1000毫秒触发在多次，也只在1000毫秒后执行一次 2、防抖和节流的实现： 14、axios的特点有哪些1、Axios 是一个基于 promise 的 HTTP 库，支持promise所有的API 2、它可以拦截请求和响应 3、它可以转换请求数据和响应数据，并对响应回来的内容自动转换成 JSON类型的数据五、大事件和node阶段1、对this的理解答: this是个关键字,它的指向和函数的调用方式有关 1. 函数调用模式, this指向window 2. 构造函数调用模式, this指向新创建的实例对象 3. 方法调用模式, this指向调用方法的对象 4. 上下文调用模式, call和apply方法中, this指向方法内的第一个参数 bind方法中, bind创建的新函数的this绑定为bind方法中新的函数 5. 在事件处理函数中,this指向触发事件的当前元素 6. 定时器中,this指向window 7. 箭头函数中没有this指向问题,它的this和外层作用域的this保持一致 8. 匿名函数中的this总是指向window2、new操作符做了什么答: 1. 创建一个新对象 2. 函数内部的this指向这个对象 3. 执行函数体 4. 自动返回这个函数 创建新的空对象 2.将构造函数中的this指向创建的新的空对象 3.执行构造函数中的代码 4.把创建的新对象给返回出去3、git如何管理一个项目1、git管理项目流程 答: 1、git init初始化git仓库（新项目才有这一步） 2、git clone将远程仓库的项目资料下载下来 3、git checkout -b dev (dev 为本地分支名） 4、git add .将工作区文件存在暂存区 4、git commit -m ""从暂存区存到仓储区 5、git checkout master切到master分支 6、git merge dev 合并分支,合并后要将分支删除 7、使用git push将其上传到远程仓库 8、第二上班，先pull一下，更新最新代码4、git如何解决合并冲突git解决合并冲突 答：冲突的原因：代码提交的时候，在当前行有新的代码要加入，就会出现冲突。例如：20行已经有代码了，但是合并的的代码20行也是有代码，这样就会出现冲突。 解决办法：如果是双方的代码是不同的业务，那就保留双方双方更改（vscode有提示）。如果是重复的业务逻辑，那就选择采用当前更改（vscode有提示）。 5、什么是promise，特点是什么 首先，它是一个对象，也就是说与其他JavaScript对象的用法，没有什么两样；它使得异步操作具备同步操作的效果，使得程序具备正常的同步运行的流程，回调函数不必再一层层嵌套。 简单说，它的思想是，每一个异步任务立刻返回一个Promise对象，由于是立刻返回，所以可以采用同步操作的流程。这个Promises对象有一个then方法，允许指定回调函数，在异步任务完成后调用。 特点： 1、Promise对象只有三种状态。 异步操作“未完成”（pending） 异步操作“已完成”（resolved，又称fulfilled） 异步操作“失败”（rejected） 异步操作成功，Promise对象传回一个值，状态变为resolved。 异步操作失败，Promise对象抛出一个错误，状态变为rejected。 2、promise的回调是同步的，then是异步的 3、可以链式调用6、promise的方法有哪些，能说明其作用原型上的方法： 1、Promise.prototype.then() 1）作用是为 Promise 实例添加状态改变时的回调函数。接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用，第二个回调函数是Promise对象的状态变为rejected时调用。其中，第二个函数是可选的，不一定要提供。 2）返回的是另一个Promise对象，后面还可以接着调用then方法。 2、Promise.prototype.catch() 1）用于指定发生错误时的回调函数。 2）返回的也是一个 Promise 对象，因此还可以接着调用then方法 3、Promise.prototype.finally() 1）finally方法用于指定不管 Promise 对象最后状态如何，都会执行的回调函数。 2）finally方法的回调函数不接受任何参数，这意味着没有办法知道，前面的 Promise 状态到底是fulfilled还是rejected。 自身API: 1、Promise.resolve() 1）不带参数传递 — 返回一个新的状态为resolve的promise对象 2）参数是一个 Promise 实例— 返回 当前的promise实例 2、Promise.reject() 1)返回的是一个值 2）返回的值会传递到下一个then的resolve方法参数中 3、Promise.all() 1）并行执行异步操作的能力 2）所有异步操作执行完后才执行回调 4、Promise.race() 1）那个结果返回来的快就是，那个结果，不管结果是成功还是失败7、async和await是干什么的1、async 用于申明一个 function 是异步的，而 await 用于等待一个异步方法执行完成。 2、await 只能出现在 async 函数中。 3、async 函数返回的是一个 Promise 对象，后面可以用then方法。8、怎么理解事件循环机制(Event Loop) 1、JavaScript 是一门单线程语言.单线程可能会出现阻塞的情况，所js分了同步任务和异步任务。 2、同步和异步任务分别进入不同的执行环境，同步的进入主线程，即主执行栈，异步的进入 Event Queue（事件队列） 。主线程内的任务执行完毕为空，会去 Event Queue 读取对应的任务，推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。9、宏任务和微任务1、先执行同步和立即执行任务，比如说console.log()、new Promise()2、再依次执行微任务，比如说then函数3、当微任务执行完成后开始执行宏任务，比如说定时器、事件回调等六、vue阶段面试题1、怎么理解mvvm这种设计模式 Model–View–ViewModel （MVVM） 是一个软件架构设计模式，是一种简化用户界面的事件驱动编程方式。 MVVM M Model 模型 指的是数据层 V View 视图 指的是用户页面 VM ViewModel 视图模型 视图模型是MVVM模式的核心，它是连接view和model的桥梁，MVVM实现了view和model的自动同步，当model的属性改变时，我们不用自己手动操作DOM元素，来改变view的显示，反之亦然，我们称之为数据的双向绑定。2、v-if和v-show的区别，使用场景区别v-if和v-show看起来似乎差不多，当条件不成立时，其所对应的标签元素都不可见，但是这两个选项是有区别的: 1、v-if在条件切换时，会对标签进行适当的创建和销毁，而v-show则仅在初始化时加载一次，因此v-if的开销相对来说会比v-show大。 2、v-if是惰性的，只有当条件为真时才会真正渲染标签；如果初始条件不为真，则v-if不会去渲染标签。v-show则无论初始条件是否成立，都会渲染标签，它仅仅做的只是简单的CSS（display）切换。 3、v-if适用于不需要频繁切换元素显示和隐藏的情况 v-show适用于需要频繁切换元素的显示和隐藏的场景。3、事件修饰符和按键修饰符有哪些事件修饰符： .prevent 阻止事件默认行为 .stop 阻止事件冒泡 .capture 设置事件捕获机制 .self 只有点击元素自身才能触发事件 .once 事件只触发一次 按键修饰符： .tab .enter .esc .space .delete(捕获"删除"和"空格"键) .up .down .left .right4、v-model修饰符有哪些.trim 去除首尾空格 .lazy 只在输入框失去焦点或按回车键时更新内容，不是实时更新 .number 将数据转换成number类型(原本是字符串类型)5、v-for中为什么要加key作用： 1.key的作用主要是为了高效的更新虚拟DOM，提高渲染性能。 2.key属性可以避免数据混乱的情况出现。 原理： 1.vue实现了一套虚拟DOM，使我们可以不直接操作DOM元素只操作数据，就可以重新渲染页面，而隐藏在背后的原理是高效的Diff算法 2.当页面数据发生变化时，Diff算法只会比较同一层级的节点； 3.如果节点类型不同，直接干掉前面的节点，再创建并插入新的节点，不会再比较这个节点后面的子节点； 如果节点类型相同，则会重新设置该节点属性，从而实现节点更新 4.使用key给每个节点做一个唯一标识，Diff算法就可以正确失败此节点，"就地更新"找到正确的位置插入新的节点。6、v-for和v-if的优先级 v-for优先级高于v-if 如果同时出现v-for和v-if，无论判断条件是否成立，都会执行一遍v-for循环，这样浪费性能，所以要尽可能的避免两者一起使用。7、组件中的data为什么是函数,new Vue 实例里，data 可以直接是一个对象1、组件是用来复用的，组件中的data写成一个函数,数据以函数返回值形式定义,函数有独立的作用域，这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。 2、而单纯的写成对象形式,由于对象是引用类型，就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。 3、因为new vue里面的代码是不存在复用的情况，所以可以写成对象形式8、computed和watch的区别是什么计算属性computed： 1、支持缓存，只有依赖数据发生改变，才会重新进行计算 2、不支持异步，当computed内有异步操作时无效，无法监听数据的变化 3、如果computed需要对数据修改，需要写get和set两个方法，当数据变化时，调用set方法。 4、computed擅长处理的场景：一个数据受多个数据影响，例如购物车计算总价 侦听属性watch： 1、不支持缓存，数据变，直接会触发相应的操作； 2、watch支持异步；监听的函数接收两个参数，第一个参数是最新的值；第二个参数是输入之前的值； 3、immediate：组件加载立即触发回调函数执行 4、deep:true的意思就是深入监听，任何修改obj里面任何一个属性都会触发这个监听器里的 handler方法来处理逻辑 5、watch擅长处理的场景：一个数据影响多个数据，例如搜索框9、组件化和模块化的区别1、组件相当于库，把一些能在项目里或者不同类型项目中可复用的代码进行工具性的封装。 2、模块相应于业务逻辑模块，把同一类型项目里的功能逻辑进行需求性的封装。10、怎么理解vue中的虚拟DOM原理： 用 JavaScript 对象模拟真实 DOM 树，对真实 DOM 进行抽象；diff 算法 — 比较两棵虚拟 DOM 树的差异；pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。 好处： 1、性能优化 2、无需手动操作DOM 3、可以跨平台，服务端渲染等11、怎么理解vue的生命周期 vue的生命周期：vue实例从创建到销毁的全过程，这个过程可以分为3个阶段 第一阶段：初始化阶段 创建vue实例,准备数据,准备模板,渲染视图 第二阶段：数据更新阶段 当数据变化时，会进行新旧DOM的对比，对比出差异的部分，进行差异化更新。 第三阶段：实例销毁阶段 当vm.$destroy()被调用，vue实例就会被销毁，释放相关资源，此时再更新数据，视图不会再变化。12、vue 钩子函数有哪些，有哪些使用的场景1、各阶段包含钩子： beforeCreate 在data数据注入到vm实例之前，此时vm身上没有数据 created 在data数据注入到vm实例之前，此时vm身上有数据 beforeMount 生成的结构替换视图之前，此时DOM还没更新 mounted 生成的结构替换视图之前，此时DOM已经更新完成 beforeUpdate 数据变化了，dom更新之前 updated 数据变化了，dom更新之后 activated 被keep-alive缓存的组件激活时调用 deactivated 被keep-alive缓存的组件停用时调用 beforeDestroy 实例销毁，是否资源之前 destroyed 实例销毁，是否资源之后这些钩子函数会在vue的生命周期的不同阶段，自动被vue调用 2、常用的钩子函数使用场景： beforeCreate 做loading的一些渲染 created 结束loading， 发送数据的请求，拿数据 mounted 可以对dom进行操作 updated 监视数据的更新 beforeDestroy 销毁非vue资源，防止内存泄漏，例如清除定时器 activated 当我们运用了组件缓存时，如果想每次切换都发送一次请求的话，需要把请求函数写在activated中，而写在created或mounted中其只会在首次加载该组件的时候起作用。13、Vue 的父组件和子组件生命周期钩子函数执行顺序1、Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下4部分： 1）加载渲染过程 :父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted 2）子组件更新过程 :父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated 3）父组件更新过程 :父 beforeUpdate -> 父 updated 4）销毁过程 :父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed 14、vue组件传值的方式1、父传子 通过props传递 父组件： <child :list = 'list' /> 子组件: props['list'],接收数据,接受之后使用和data中定义数据使用方式一样 2、子传父 :在父组件中给子组件绑定一个自定义的事件，子组件通过$emit()触发该事件并传值。 父组件： <child @receive = 'getData' /> getData(value){value就是接收的值} 子组件: this.$emit('receive',value) 3、兄弟组件传值通过中央通信 let bus = new Vue() A组件：methods :{ sendData(){ bus.$emit('getData',value) } 发送 B组件：created(){ bus.$on(‘getData’,(value)=>{value就是接收的数据}) } 进行数据接收15、$nextTick是什么？原理是什么背景： 1、简单来说，Vue 在修改数据后，视图不会立刻更新，而是等同一事件循环中的所有数据变化完成之后，再统一进行视图更新。 定义： 2、在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法，获取更新后的 DOM。nextTick()，是将回调函数延迟在下一次dom更新数据后调用，简单的理解是：当数据更新了，在dom中渲染后，自动执行该函数。 原理 3、vue用异步队列的方式来控制DOM更新和nextTick回调先后执行。 简单来说，nextTick是做了promise加上setTimeout的封装,利用事件换行机制，来确保当nextTick出现时，都是在我们所有操作DOM更新之后的场景 4.1 点击获取元素宽度 4.2 使用swiper插件通过 ajax 请求图片后的滑动问题 4.3 点击按钮显示原本以 v-show = false 隐藏起来的输入框，并获取焦点16、vue是如何获取DOM1、先给标签设置一个ref值，再通过this.$refs.domName获取，这个操作要在mounted阶段进行。 2、例如： mounted(){ const dom = this.$refs.test }17、v-on可以监听多个方法吗可以例如： 18、谈谈你对 keep-alive 的了解1、keep-alive 是 Vue 内置的一个组件，可以使被包含的组件保留状态，避免重新渲染 2、一般结合路由和动态组件一起使用，用于缓存组件 3、对应两个钩子函数 activated 和 deactivated ，当组件被激活时，触发钩子函数 activated，当组件被移除时，触发钩子函数 deactivated 4、 include 字符串，数组或正则表达式。只有名称匹配的组件会被缓存。 exclude 字符串，数组或正则表达式。任何名称匹配的组件都不会缓存。 max 数字。最多可以缓存多少组件实例。 其中 exclude 的优先级比 include 高； 例如： include: <keep-alive include="a"> <component></component> </keep-alive> exclude: <keep-alive exclude="a"> <component></component> </keep-alive>19、谈谈你对slot的了解1、什么是插槽 (1) 插槽（Slot）是Vue提出来的一个概念，正如名字一样，插槽用于决定将所携带的内容，插入到指定的某个位置，从而使模板分块，具有模块化的特质和更大的重用性。 (2) 插槽显不显示、怎样显示是由父组件来控制的，而插槽在哪里显示就由子组件来进行控制 2、插槽使用 (1) 默认插槽 在子组件中写入slot，slot所在的位置就是父组件要显示的内容 (2) 具名插槽 在子组件中定义了三个slot标签，其中有两个分别添加了name属性header和footer 在父组件中使用template并写入对应的slot名字来指定该内容在子组件中现实的位置 (3) 作用域插槽 在子组件的slot标签上绑定需要的值<slot :data="user"></slot> 在父组件上使用slot-scope=“user”来接收子组件传过来的值 20、vue中动态组件如何使用1、在某个中使用 is 特性来切换不同的组件： <component :is="TabComponent"></component> TabComponent:已注册组件的名字21、v-model的原理是什么1、v-model主要提供了两个功能，view层输入值影响data的属性值，属性值发生改变会更新层的数值变化. 2、v-model指令的实现： 3.1 v-bind:绑定响应式数据 3.2 触发input事件并传递数据 (核心和重点)3、其底层原理就是(双向数据绑定原理)： 3.1 一方面modal层通过defineProperty来劫持每个属性，一旦监听到变化通过相关的页面元素更新。 3.2 另一方面通过编译模板文件，为控件的v-model绑定input事件，从而页面输入能实时更新相关data属性值。22、vue响应式的原理1、原理： Vue 的响应式原理是核心是通过 ES5 的 Object.defindeProperty 进行数据劫持，然后利用 get 和 set 方法进行获取和设置，data 中声明的属性都被添加到了get和set中，当读取 data 中的数据时自动调用 get 方法，当修改 data 中的数据时，自动调用 set 方法，检测到数据的变化，会通知观察者 Wacher，观察者 Wacher自动触发重新render 当前组件（子组件不会重新渲染）,生成新的虚拟 DOM 树，Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别，并记录下来，最后，加载操作，将所有记录的不同点，局部修改到真实 DOM 树上。 2、底层代码实现： let data = { name: "lis", age: 20, sex: "男" } vue2.0实现： 使用Object.defineProperty进行数据劫持 for(let key in data){ let temp = data[key] Object.defineProperty(data, data[key], { get(){ return temp}, set(value){temp = value} } )} vue3.0实现 : 使用Proxy 进行数据的代理 let newData = new Proxy(data, {get(target, key){ return target[key]} set(target, key, value) { target[key] = value } })23、vue2.0和vue3.0响应式的区别1、Object.defineProperty (1) 用于监听对象的数据变化 (2) 无法监听数组变化(下标，长度) (3) 只能劫持对象的自身属性，动态添加的劫持不到 2、Proxy (1) proxy返回的是一个新对象， 可以通过操作返回的新的对象达到目的 (2)可以监听到数组变化，也可以监听到动态添加的数据24、router和route的区别1.$router对象 $router对象是全局路由的实例，是router构造方法的实例 $router对象上的方法有：push()、go()、replace() 2、$route对象 $route对象表示当前的路由信息，包含了当前 URL 解析得到的信息。包含当前的路径， $route对象上的属性有：path、params、query、hash等等 25、路由传参的方式和区别1、方式：params 和 query 2、区别： （1）params用的是name，传递的参数在地址栏不会显示，类似于post （2）query用的是path,传递的参数会在地址栏显示出来，类似于get 3、举例说明： （1）params 传参 传： this.$router.push({ name: 'particulars', params: { id: id } }) 接：this.$route.params.id （2）.query传参 传：this.$router.push({ path: '/particulars', query: { id: id } }) 接：this.$route.query.id26、Vue模版编译原理知道吗，能简单说一下吗1、简单说，Vue的编译过程就是将template转化为render函数的过程。 2、首先解析模版，生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。 使用大量的正则表达式对模板进行解析，遇到标签、文本的时候都会执行对应的钩子进行相关处理。 3、Vue的数据是响应式的，但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化，对应的DOM也不会变化。那么优化过程就是深度遍历AST树，按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对，对运行时的模板起到很大的优化作用。4、编译的最后一步是将优化后的AST树转换为可执行的代码。27、SSR了解吗1、SSR也就是服务端渲染，也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成，然后再把html直接返回给客户端。 2、SSR有着更好的SEO、并且首屏加载速度更快等优点。 3.缺点：比如我们的开发条件会受到限制，服务器端渲染只支持beforeCreate和created两个钩子 当我们需要一些外部扩展库时需要特殊处理，服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器的压力比较大。28、你都做过哪些Vue的性能优化1、v-if和v-for不能连用 2、页面采用keep-alive缓存组件 3、合理使用v-if和v-show 4、key保证唯一 5、使用路由懒加载、异步组件、组件封装 6、防抖、节流 7、第三方模块按需导入 8、图片懒加载 9、精灵图的使用 10、代码压缩29、Vue-router 路由有哪些模式一般有两种模式： 1、hash 模式：后面的 hash 值的变化，浏览器既不会向服务器发出请求，浏览器也不会刷新， 每次 hash 值的变化会触发 hashchange 事件。 2、history 模式：利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。 这两个方法应用于浏览器的历史记录栈，在当前已有的 back、forward、go 的基础之上，它们提供了对历史记录进行修改的功能。只是当它们执行修改时，虽然改变了当前的 URL，但浏览器不会立即向后端发送请求。30、Vuex 是什么？有哪几种属性？1、Vuex 是专为Vue设计的状态管理工具，采用集中式储存管理 Vue 中所有组件的状态。 2、属性 （1）state属性：基本数据 （2）getters属性：从 state 中派生出的数据 （3）mutation属性：更新 store 中数据的唯一途径，其接收一个以 state 为第一参数的回调函数 （4）action 属性：提交 mutation 以更改 state，其中可以包含异步操作，数据请求 （5）module 属性：用于将 store分割成不同的模块。31、axios封装请求拦截器和响应拦截器interceptors：【ɪntərˈsɛptərz】 1、项目中会在utils文件中，封装一个request.js文件 2、通过axios.create()配置baseURL，并得到一个request实例 3、通过request.interceptors.request.use来配置请求拦截 4、通过request.interceptors.response.use来配置响应拦截32、webpack在项目中的常见配置1、 配置兼容编译ES6转成ES5 用babel来编译， npm i babel-core babel-loader babel-preset-env babel-polyfill babel-plugin-transform-runtime --save-dev 2、配置跨域代理服务 用proxy进行代理，在devServer里面配置， proxy:{ '/api':{target:代理的地址} } 3、配置打包路径 publicPath:'/' 4、配置打包出去文件 outputDir: 'dist' 5、配置执行环境变量 启动的端口 const port = process.env.port || process.env.npm_config_port || 9528 33、vue怎么实现强制刷新组件第一.使用this.$forceUpdate强制重新渲染 刷新当前组件 第二.使用v-if指令 <comp v-if="update"></comp> 刷新comp组件 34、在使用计算属性的时,函数名和data数据源中的数据可以同名吗?不可以 在初始化vm的过程，因为不管是计算属性还是data还是props 都会被挂载在vm实例上，会把data覆盖了,因此 这三个都不能同名35、vue中data的属性可以和methods中的方法同名吗?不可以 vue源码中的 initData() 方法会取出 methods 中的方法进行判断，如果有重复的就会报错36、你知道style加scoped属性的用途和原理吗用途：防止全局同名CSS污染原理：在标签加上v-data-something属性，再在选择器时加上对应[v-data-something]，即CSS带属性选择器，以此完成类似作用域的选择方式. scoped会在元素上添加唯一的属性（data-v-x形式），css编译后也会加上属性选择器，从而达到限制作用域的目的。37、如何在子组件中访问父组件的实例Vue中子组件调用父组件的方法，这里有三种方法提供参考： 1：直接在子组件中通过this.$parent.event来调用父组件的方法 2：在子组件里用$emit向父组件触发一个事件，父组件监听这个事件 3：父组件把方法传入子组件中，在子组件里直接调用这个方法38、watch的属性用箭头函数定义结果会怎么样不应该使用箭头函数来定义 watch :例如： watch: { a: () => { // 这里不应该用箭头函数 console.log(this); this.sum = this.a + this.b; } })。 理由是箭头函数绑定了父级作用域的上下文，所以 this 将不会按照期望指向 Vue 实例，this.a 将是 undefined。注意：methods里面定义的方法也不要用箭头函数40、怎么解决vue打包后静态资源图片失效的问题在vue-cli 需要在根目录下建一个vue.config.js 在里面配置publicPath即可默认值为/，更改为./就好了41、怎么解决vue动态设置img的src不生效的问题因为动态添加src被当做静态资源处理了，没有进行编译，所以要加上require。 42、EventBus注册在全局上时，路由切换时会重复触发事件，如何解决呢原因：因为我们的事件是全局的，它并不会随着组件的销毁而自动注销，需要我们手动调用注销方法来注销。解决：我们可以在组件的 beforeDestroy ,或 destroy 生命周期中执行注销方法，手动注销事件43、你认为vue的核心是什么组件化双向数据绑定44、在.vue文件中style是必须的吗？那script是必须的吗在.vue 文件中，template是必须的，而script与style都不是必须的。都没有的话那就是一个静态网页45、说说vue的优缺点优点： 1.数据驱动 2.组件化 3.轻量级 4.SPA(单页面) 5.版本3.0的界面化管理工具比较好使 6.vue易入门 7.中文社区强大，入门简单，提升也有很多的参考资料。缺点： 1.不支持IE8及以下浏览器 2.吃内存（每个组件都会实例化一个Vue实例，实例的属性和方法很多） 3.定义在data里面的对象，实例化时，都会递归的遍历转成响应式数据，然而有的响应式数据我们并不会用到， 造成性能上的浪费七、react高频面试题1、什么是虚拟DOM？ 虚拟 DOM (VDOM)是真实 DOM 在内存中的表示。UI 的表示形式保存在内存中，并与实际的 DOM 同步。这是一个发生在渲染函数被调用和元素在屏幕上显示之间的步骤，整个过程被称为调和。2、虚拟DOM实现的原理？1.虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象 2.状态变更时，记录新树和旧树的差异 3.最后把差异更新到真正的dom中3、类组件和函数组件之间的区别是啥？ 类组件可以使用其他特性，如状态 state 和生命周期钩子。 当组件只是接收 props 渲染到页面时，就是无状态组件，就属于函数组件，也被称为哑组件或展示组件。 函数组件和类组件当然是有区别的，而且函数组件的性能比类组件的性能要高，因为类组件使用的时候要实例化，而函数组件直接执行函数取返回结果即可。如果都能满足需求的情况下，为了提高性能，尽量使用函数组件。4、React 中 refs 干嘛用的？ Refs 提供了一种访问在render方法中创建的 DOM 节点或者 React 元素的方法。 可以在组件添加一个 ref 属性来使用，该属性的值是一个回调函数，接收作为其第一个参数的底层 DOM 元素或组件的挂载实例。5、在 React 中如何处理事件？ 为了解决跨浏览器的兼容性问题，SyntheticEvent(事件e) 实例将被传递给你的事件处理函数，SyntheticEvent是 React 跨浏览器的浏览器原生事件包装器，它还拥有和浏览器原生事件相同的接口，包括 stopPropagation() 和 preventDefault()。6、state 和 props 区别是啥？ props和state是普通的 JS 对象。虽然它们都包含影响渲染输出的信息，但是它们在组件方面的功能是不同的。即 1.state 是组件自己管理数据，控制自己的状态，可变； 2.props 是外部传入的数据参数，不可变； 3.没有state的叫做无状态组件，有state的叫做有状态组件； 4.多用 props，少用 state，也就是多写无状态组件。7、如何创建 refs？Refs 是使用 React.createRef() 创建的，并通过 ref 属性附加到 React 元素。在构造组件时，通常将 Refs 分配给实例属性，以便可以在整个组件中引用它们。8、什么是高阶组件？高阶组件(HOC)是接受一个组件并返回一个新组件的函数。基本上，这是一个模式，是从 React 的组合特性中衍生出来的，称其为纯组件，因为它们可以接受任何动态提供的子组件，但不会修改或复制输入组件中的任何行为。9、在构造函数调用 super 并将 props 作为参数传入的作用是啥？在调用 super() 方法之前，子类构造函数无法使用this引用，ES6 子类也是如此。将 props 参数传递给 super() 调用的主要原因是在子构造函数中能够通过this.props来获取传入的 props。10、什么是控制组件？ 在 HTML 中，表单元素如 、 和 通常维护自己的状态，并根据用户输入进行更新。当用户提交表单时，来自上述元素的值将随表单一起发送。 而 React 的工作方式则不同。包含表单的组件将跟踪其状态中的输入值，并在每次回调函数(例如onChange)触发时重新渲染组件，因为状态被更新。以这种方式由 React 控制其值的输入表单元素称为受控组件。11、讲讲什么是 JSX ？jsx是JavaScript的一种语法扩展，它跟模板语言很接近，但是它充分具备JavaScript的能力 当 Facebook 第一次发布 React 时，他们还引入了一种新的 JS 方言 JSX， 将原始 HTML 模板嵌入到 JS 代码中。 JSX 代码本身不能被浏览器读取，必须使用Babel和webpack等工具将其转换为传统的JS。 JSX中的标签可以是单标签，也可以是双标签，但必须保证标签是闭合的。12、为什么不直接更新 state 呢 ?如果试图直接更新 state ，则不会重新渲染组件。 需要使用setState()方法来更新 state。它调度对组件state对象的更新。当state改变时，组件通过重新渲染来响应。13、React 组件生命周期有哪些不同阶段？在组件生命周期中有四个不同的阶段 1.Initialization：在这个阶段，组件准备设置初始化状态和默认属性。 2.Mounting：react 组件已经准备好挂载到浏览器 DOM 中。这个阶段包括componentWillMount和componentDidMount生命周期方法。 3.Updating：在这个阶段，组件以两种方式更新，发送新的 props 和 state 状态。此阶段包括shouldComponentUpdate、componentWillUpdate和componentDidUpdate生命周期方法。 4.Unmounting：在这个阶段，组件已经不再被需要了，它从浏览器 DOM 中卸载下来。这个阶段包含 componentWillUnmount 生命周期方法。除以上四个常用生命周期外，还有一个错误处理的阶段 5.Error Handling：在这个阶段，不论在渲染的过程中，还是在生命周期方法中或是在任何子组件的构造函数中发生错误，该组件都会被调用。这个阶段包含了 componentDidCatch 生命周期方法。14、React 的生命周期方法有哪些？1.componentWillMount:在渲染之前执行，用于根组件中的 App 级配置。 2.componentDidMount：在第一次渲染之后执行，可以在这里做AJAX请求，DOM 的操作或状态更新以及设置事件监听器。 3.componentWillReceiveProps：在初始化render的时候不会执行，它会在组件接受到新的状态(Props)时被触发，一般用于父组件状态更新时子组件的重新渲染 4.shouldComponentUpdate：确定是否更新组件。默认情况下，它返回true。如果确定在 state 或 props 更新后组件不需要在重新渲染，则可以返回false，这是一个提高性能的方法。 5.componentWillUpdate：在shouldComponentUpdate返回 true 确定要更新组件之前件之前执行。 6.componentDidUpdate：它主要用于更新DOM以响应props或state更改。 7.componentWillUnmount：它用于取消任何的网络请求，或删除与组件关联的所有事件监听器。15、使用 React Hooks 好处是啥？首先，Hooks 通常支持提取和重用跨多个组件通用的有状态逻辑，而无需承担高阶组件或渲染 props 的负担。Hooks 可以轻松地操作函数组件的状态，而不需要将它们转换为类组件。 Hooks 在类中不起作用，通过使用它们，咱们可以完全避免使用生命周期方法， 例如 componentDidMount、componentDidUpdate、componentWillUnmount。 相反，使用像useEffect这样的内置钩子。16、什么是 React Hooks？Hooks是 React 16.8 中的新添加内容。它们允许在不编写类的情况下使用state和其他 React 特性。使用 Hooks，可以从组件中提取有状态逻辑，这样就可以独立地测试和重用它。Hooks 允许咱们在不改变组件层次结构的情况下重用有状态逻辑，这样在许多组件之间或与社区共享 Hooks 变得很容易。17、React 中的 useState() 是什么？useState 是一个内置的 React Hook。useState(0) 返回一个元组，其中第一个参数count是计数器的当前状态，setCounter 提供更新计数器状态的方法。 可以在任何地方使用setCounter方法更新计数状态-在这种情况下，咱们在setCount函数内部使用它可以做更多的事情，使用 Hooks，能够使咱们的代码保持更多功能，还可以避免过多使用基于类的组件。18、React 中的StrictMode(严格模式)是什么？React 的StrictMode是一种辅助组件，可以帮助咱们编写更好的 react 组件，可以使用<StrictMode />包装一组组件，并且可以帮咱们以下检查： 1.验证内部组件是否遵循某些推荐做法，如果没有，会在控制台给出警告。 2.验证是否使用的已经废弃的方法，如果有，会在控制台给出警告。 3.通过识别潜在的风险预防一些副作用。19、为什么类方法需要绑定到类实例？在 JS 中，this 值会根据当前上下文变化。 在 React 类组件方法中，开发人员通常希望 this 引用组件的当前实例， 因此有必要将这些方法绑定到实例。20、受控组件和非受控组件区别是啥？受控组件是 React 控制中的组件， 并且是表单数据真实的唯一来源。非受控组件是由 DOM 处理表单数据的地方，而不是在 React 组件中. 尽管非受控组件通常更易于实现，因为只需使用refs即可从 DOM 中获取值，但通常建议优先选择受控制的组件，而不是非受控制的组件。这样做的主要原因是受控组件支持即时字段验证，允许有条件地禁用/启用按钮，强制输入格式。21、如何避免组件的重新渲染？React 中最常见的问题之一是组件不必要地重新渲染。 React 提供了两个方法，在这些情况下非常有用： 1.React.memo():这可以防止不必要地重新渲染函数组件 2.PureComponent:这可以防止不必要地重新渲染类组件 这两种方法都依赖于对传递给组件的props的浅比较，如果 props 没有改变，那么组件将不会重新渲染。 虽然这两种工具都非常有用，但是浅比较会带来额外的性能损失，因此如果使用不当，这两种方法都会对性能产生负面影响。 通过使用 React Profiler，可以在使用这些方法前后对性能进行测量，从而确保通过进行给定的更改来实际改进性能。22、如何避免在React重新绑定实例(解决this指向)？有几种常用方法可以避免在 React 中绑定方法： 1)将事件处理程序定义为内联箭头函数 2)使用箭头函数来定义方法 3)使用带有 Hooks 的函数组件23、React组件通信如何实现?React组件间通信方式: 1.父组件向子组件通讯: 父组件可以向子组件通过传 props 的方式，向子组件进行通讯 2.子组件向父组件通讯: props+回调的方式,父组件向子组件传递props进行通讯，此props为作用域为父组件自身的函数，子组件调用该函数，将子组件想要传递的信息，作为参数，传递到父组件的作用域中 3.兄弟组件通信: 找到这两个兄弟节点共同的父节点,结合上面两种方式由父节点转发信息进行通信 4.跨层级通信: Context设计目的是为了共享那些对于一个组件树而言是“全局”的数据，例如当前认证的用户、主题或首选语言,对于跨越多层的全局数据通过Context通信再适合不过 5.发布订阅模式: 发布者发布事件，订阅者监听事件并做出反应,我们可以通过引入event模块进行通信 6.全局状态管理工具: 借助Redux或者Mobx等全局状态管理工具进行通信,这种工具会维护一个全局状态中心Store,并根据不同的事件产生新的状态24、React如何进行组件/逻辑复用?1)高阶组件: (1)属性代理 (2)反向继承2)渲染属性3)react-hooks25、redux的工作流程?首先，我们看下几个核心概念： 1.Store：保存数据的地方，你可以把它看成一个容器，整个应用只能有一个Store。 2.State：Store对象包含所有数据，如果想得到某个时点的数据，就要对Store生成快照，这种时点的数据集合，就叫做State。 3.Action：State的变化，会导致View的变化。但是，用户接触不到State，只能接触到View。所以， 4.State的变化必须是View导致的。Action就是View发出的通知，表示State应该要发生变化了。 5.Action Creator：View要发送多少种消息，就会有多少种Action。如果都手写，会很麻烦，所以我们定义一个函数来生成Action，这个函数就叫Action Creator。 6.Reducer：Store收到Action以后，必须给出一个新的State，这样View才会发生变化。这种State的计算过程就叫做Reducer。Reducer是一个函数，它接受Action和当前State作为参数，返回一个新的State。 7.dispatch：是View发出Action的唯一方法。然后整个工作流程： (1)首先，用户（通过View）发出Action，发出方式就用到了dispatch方法。 (2)然后，Store自动调用Reducer，并且传入两个参数：当前State和收到的Action，Reducer会返回新的State。 (3）State一旦有变化，Store就会调用监听函数，来更新View。26、redux中如何进行异步操作?当然,我们可以在componentDidmount中直接进行请求无须借助redux. 但是在一定规模的项目中,上述方法很难进行异步流的管理,通常情况下我们会借助redux的异步中间件进行异步处理. redux异步流中间件其实有很多,但是当下主流的异步中间件只有两种redux-thunk、redux-saga，当然redux-observable可能也有资格占据一席之地,其余的异步中间件不管是社区活跃度还是npm下载量都比较差了。
import { getToken } from '@/utils/tokenApi' import { Redirect, Route, RouteProps, useLocation } from 'react-router-dom' interface PrivateRouteType extends RouteProps { component: any } // children传入组件 component标签传组件 function PrivateRoute({ children, component: Component, ...rest }: PrivateRouteType) { const location = useLocation() return ( <Route {...rest} render={() => { // 查看本地是否有token 获取token const token = getToken() // 如果有 就去传递过来的组件 if (token.token) { return children ? children : <Component></Component> } else { // 没有就去login state/from 记录拦截下来的地址 用于回调 return ( <Redirect to={{ pathname: '/login', // state传参 state: { form: location.pathname }, }} ></Redirect> ) } }} /> ) } export default PrivateRoute
React、Vue项目中Token无感刷新原理-实用大多数项目
// 添加请求拦截器 request.interceptors.request.use( function (config) { // 在发送请求之前做些什么 const token = getToken().token if (token) { config.headers!.Authorization = `Bearer ${token}` } return config }, function (error) { // 对请求错误做些什么 return Promise.reject(error) } ) // 添加响应拦截器 request.interceptors.response.use( function (response) { // 对响应数据做点什么 return response }, async function (error: AxiosError<{ message: string }>) { console.dir(error, '99999') // 无感刷新回答： // 后台返回401， // 响应拦截器中处理 => 判断是否是有token // 如果有 说明token过期了 => 尝试用refresh_token 发请求刷新token // 刷新成功， 保存到本地以及仓库中 并重新发请求 // 刷新失败， 说明refresh_token 也过期了 则跳转到登录页 // 理解 ：用户发起一个请求， // 情况1：请求成功正常拿到数据，正常渲染 // 情况2: 没有返回结果 说明服务器有误，提示用户 // 情况3: 后端返回401 说明token过期,请求拦截器中判断返回结果是否为401， // 如果是401则，尝试利用refresh_token发送一个刷新token请求 // 拿回新token 基于新的token在发送上一个响应错误的请求, // 如果没有拿到新的token 则说明refresh_token也过期,跳转登录页 // 如果本地根本没有token，请直接拦截到登录页 // 对响应错误做点什么 // !----------------情况1：服务器繁忙------------ if (!error.response) { // 如果没有响应信息 Toast.show({ content: '服务器繁忙,请稍后重试', duration: 3000, }) return Promise.reject(error) } // !----------------情况2：token过期---------------- const token = getToken() // 判断是否为401 if (error.response.status === 401) { // 是的话判断本地有没有refresh_token // 如果有token 发送请求获取新的token if (token.refresh_token) { try { // 获取新的token const res = await axios({ method: 'put', url: baseURL + '/authorizations', headers: { Authorization: 'Bearer ' + token.refresh_token, }, }) // 拿到新token 存入仓库 store.dispatch( savetoken({ // token为最新获取的token token: res.data.data.token, // refresh_token是从本地获取的 refresh_token: token.refresh_token, }) ) // 存入成功后 重新发送错误请求 return request.request(error.config) } catch (error) { // !----------------情况3：refresh_token过期---------------- // 如果失败说明 refresh_token也过期 重新登录 Toast.show({ content: '登录信息过期,请重新登录', }) // 清除现有的所有的token store.dispatch(LogOut()) // 携带当前路径 直接跳转 history.replace({ pathname: '/login', state: { form: history.location.pathname, }, }) } return Promise.reject(error) } else { // !----------------情况4：根本没有token---------------- // 如果没有直接跳 Toast.show({ content: '登录认证失效', }) // 携带当前路径 直接跳转 history.replace({ pathname: '/login', state: { form: history.location.pathname, }, }) return Promise.reject(error) } } // 提示用户错误信息 Toast.show({ content: error.response?.data.message, duration: 3000, }) return Promise.reject(error) } )
function itheima(options) { // 创建构造函数 const xhr = new XMLHttpRequest(); // 打印形参 console.log(options); // 打印 看看 // console.log(options.params); // 如果查询参数有值 判断查询还是新增 if (options.params) { // console.log(options.params); // 定义数组 装着对象的值 let qs = []; // 遍历对象获取key for (let key in options.params) { // 获取键 // console.log(key); // 获取值 // console.log(options.params[key]); // 将键值对拼接 添加到数组中 qs.push(`${key}=${options.params[key]}`); } // 打印看看qs数组的值 console.log(qs); if (qs.length > 0) { // 看看join 转换后的拼接的字符串 // console.log(qs.join('&')); // 把 options.url的值 赋给 xhr.open() // options.url = options.url + `?${qs.join('&')}`; // 简化写法 options.url += `?${qs.join('&')}`; // 打印看看 // console.log(options.url); } } // 将形参中的值 请求方法 请求地址 放入请求中 xhr.open(options.method, options.url); // 判断请求类型 // 先把用户输入的请求方式 转为大写字母 并且 不是GET请求 并且 有data新增对象 if (options.method.toUpperCase() !== 'GET' && options.data) { // 1.判断是否为 FormData if (options.data instanceof FormData) { console.log(options.data); xhr.send(options.data); } // 2.判断data是否为字符串类型 else if (typeof options.data === 'string') { // 定义请求类型 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(options.data); } // 3.判断data是否为对象类型 else if (typeof options.data === 'object') { // 定义请求类型 xhr.setRequestHeader('Content-Type', 'application/json'); // xhr.send(options.data); xhr.send(JSON.stringify(options.data)); } } else { xhr.send(); } // 发送请求 // 监听结果 xhr.addEventListener('load', function () { // console.log(JSON.parse(xhr.response)); // 将结果字符串转为对象 const res = JSON.parse(xhr.response); // 返回给 success 函数 传实参 options.success(res); }); }