2023年度技术盘点-前端技术总结

425 阅读31分钟

目录

1. 前端基础

2. JS 数据类型、常用方法

3. Vue 常用方法

4. Webpack 常用方法

5. Node 常用方法

6. JS 高频面试题汇总

一, 前端基础

1.1 起源零 浏览器制定规则 本来面目 ("道")

包括三部分: html css js , 举例子: 也就是 结构 \ 样式 \ js交互(操作结构和样式和数据处理)

1.2 进化一 JQ 问世

DOM 操作更方便, 在原生 JS 封装了一些方法。技术发展演变,可能就由于 设计模式,性能等原因, DOM操作频繁,引起太多的重绘和回流, 最终在2015 年开始陆续被取代, 不过确实挺好用的, 也很简单!

1.3 进化二 vue react 小程序 混合应用

对应到 vue 中就是 template style methods props, 只不过加入了router, MVVM, 双向绑定, 模板解析, 虚拟DOM树(就是个JS对象) , diff 算法, 生命周期, 组件, 打包等操作,最终生成的【也一样最终处理完就是 html css js】,这个规则是浏览器定的, 我们的框架只能去适应!

各种小程序, react 也是类似

在这期间vue 项目已经可以一套代码,同时在手机浏览器,电脑上访问了,但是,这个用户体验是不行的.所以,小程序出现了.混合开发的方式风靡一段时间.

混合应用, 在原生软件内部嵌入 H5 项目.大大提升了效率.但是,核心的业务还是原生的稳妥.

1.4 进化三 多端框架 taro uniapp reactnative flutter 等

多端框架 taro uniapp 等, 前者是用 react 语法, 后者是用 vue 语法

出现的原因就是为了降本增效, 一套代码,各个平台的小程序,直接都生成了。这也是互联网企业巨头的竞争都要搞自己的小程序,那么,就会有人出来解决问题.

flutter 在北京一直就不火, 很多大厂都不用, 可能一些不重要的项目,拿来测试一下, 小企业就更不用说了. 我也没怎么用过, 听说是 配套不行, 开发体验不行,文档,周边不行. 好像问题不小啊.汗

reactnative 在京东的时候用过,不过很少有项目用.

1.5 前端周边进化列表如下

1.5.1 前端周边进化

随着技术的发展,周边也在偶尔借助 nodeJS 不断升级,总之,是越来越方便/规范化了, 一个命令创建一个项目, 一个命令打包,一个命令部署到各个环境.

  1. 项目的创建方式
  2. 打包方式(webpack项目用 , rollup类库用)
  3. 部署方式

1.5.2 开发工具的升级

  1. 我记得2012 年那会用过上学时的 dreamweaver , sublime
  2. 用过后端的开发工具 idea, Eclipse
  3. 后面基本上都是 VScode 用的最多

1.5.3 版本管理工具的升级

  1. 我记得2012 年那会用过 svn
  2. 之后基本上都是 git 还有一个可视化界面的 git 工具, svn 好像用的越来越少了, 不过感觉很亲切

1.5.4 前端本地启动服务工具

  1. 2012年用过 tomcat ,每个前端都应该安装过
  2. 后面,基本都是 node 了, node 也越来越火

1.5.5 模块化工具( 代码管理 依赖管理 编译时机)

  1. requirejs/seajs: 是一种在线“编译”模块的方案,相当于在页面上加载一个CommonJS/AMD模块格式解释器。这样浏览器就认识了define, exports,module这些东西,也就实现了模块化。------JQ 时代配套用的

2.browserify/webpack:是一个预编译模块打包的方案,相比于第一种方案,这个方案更加智能。由于是预编译的,不需要在浏览器中加载解释器。你在本地直接写JS,不管是AMD/CMD/ES6风格的模块化,它都能认识,并且编译成浏览器认识的JS

1.5.5 样式文件 与 尺寸单位

样式文件

less, sass, stylus 动态样式语言,比css多出了很多功能(如变量,计算,混入,颜色处理,函数,继承, 嵌套等), 更方便的写样式文件. 你写的和你看到的不太一样. 因为有变量,混入等. 不过最后都需要使用一个 webpack loader 来编译成 css 文件.

比如less-loader 等, 都是把它的语法通过 语法树的解析 转换 生成 最终的 CSS

就和 把 VUE 文件转换成 HTML JS CSS 是一回事,都需要通过正则解析 其中的模板template, JS 也是需要提取出来, 按照生命周期的顺序 生成最终的 JS 文件. 然后在压缩合并, 并且可以动态加载指定的用到的 JS

  1. css
  2. less
  3. sass
  4. stylus

尺寸单位

  1. px
  2. rpx
  3. rem

1.5.6 兼容性

  1. 2011年到2015年左右, 调了很多 IE 的兼容性问题
  2. 之后,调了很多 混合应用 H5 的兼容性问题, 需要配置, 实时调试,实时在模拟器上看在不同手机上的展示效果
  3. 多机型兼容性调试

1.5.7 性能优化

为什么要优化 如何优化

代码本身

  • js文件放到文件页面底部,避免阻塞页面渲染
  • 使用事件委托,减少事件绑定次数。
  • 合理使用缓存,避免重复请求数据。
  • 2012年的时候,对于代码规划,大家没有那么在意, 后来,发现代码没法维护, 没有标准,大家就很任性的写
  • 命名语意化,按照标准去写
  • 不要重复封装方法, 能复用的就复用
  • vue 就遵循 vue 的规范, 比如 合理使用watchcomputed, 合理使用v-if v-show,
  • 使用异步组件,避免一次性加载太多组件
  • 避免使用v-html,存在安全问风险和性能问题,可以使用v-text
  • 使用keep-alive缓存组件,避免组件重复加载

Webpack优化

  • 代码切割,使用code splitting将代码进行分割,避免将所有代码打包到一个文件,减少响应体积。
  • 按需加载代码,在使用使用的时候加载代码。
  • 压缩代码体积,可以减小代码体积
  • 优化静态资源,使用字体图标、雪碧图、webp格式的图片、svg图标等
  • 使用Tree Shaking 删除未被引用的代码
  • 开启gzip压缩
  • 静态资源使用CDN加载,减少服务器压力

网络优化

  • 使用HTTP/2
  • 减少、合并HTTP请求,通过合并CSS、JS文件、精灵图等方式减少请求数量。
  • 压缩文件, 开启nginxGzip对静态资源压缩
  • 使用HTTP缓存,如强缓存、协商缓存
  • 使用CDN,将网站资源分布到各地服务器上,减少访问延迟
  • 图片懒加载 (动态替换 SRC)
  • 加载了用不到的文件,包括图片,css, js
  • 发了没必要发的请求
  • 异步加载JS

事件触发优化

1. 节流

函数在 n 秒内只执行一次,如果多次触发,则忽略执行。

应用场景

  • 拖拽场景
  • scroll场景
  • 窗口大小调整

2. 防抖

函数在 n 秒后再执行,如果 n 秒内被触发,重新计时,保证最后一次触发事件 n 秒后才执行。 应用场景

  • 输入框搜索
  • 表单提交按钮
  • 文本器保存

为什么要优化

  • 提高用户体验
  • 增加页面访问量
  • 提高搜索引擎排名
  • 减少服务器压力
  • 节约成本
  • 提高用户留存率

1.5.8 组件库

  1. elementUI
  2. uni ui
  3. 各种 UI 组件库

js 数据类型、常用方法

2.1 数据类型

分为值类型引用类型;



数据类型判断:

  1. typeof 可以区分出值类型;
  2. Object.prototype.toString.call(a) === '[]'; // '[object Array]'

2.2 常用方法

最常用的除了值类型, 就是 数组, 对象 相关的方法了.

会的方法不图多, 会几个好用的即可.

抓住重点, 无非就是处理后端返回的数据,前端的业务代码,工具代码, 基本类型没啥注意的, 引用类型,数组,对象常用的方法就那几个. 万变不离其宗

对于,前端来说, 不用太用力在这方面.除非你做的是工具类, 可以锻炼一个算法思维, 可能用到,但是不多.

注意

字符串 和 数组 同名让方法有 slice indexOf concat incluldes toString

String 字符串

字符串常用的API方法包括查找、截取、替换、分割、大小写转换、字符串拼接和字符串比较等等

正则表达式的常用方法,包括test、exec、match、replace等. 匹配指定规则的字符串.

字符串的 增删改查

【增】拼接 +concat

const str = "abc";
const str1 = "def";
res = str+str1;  // 'abcdef'


str.concat(str1,str); // 'abcdefabc'

【改】【删】截取 substr(不常用) substring slice

substring slice 两者入参方式类似.并且都不改变原字符串.

此类方法处理参数的边界较多. 比如,入参太大,太小,缺少参数, 为负数等等情况. 负数从尾部开始计算.

substr()方法返回从指定位置开始的字符串中指定字符数的字符,str.substr(start, [length])

const str = "abcdef";
str.substr(2, 1); // 'c'

substring(start, end)方法接受两个参数,第一个参数是起始位置,第二个参数是结束位置,截取的字符串不包括结束位置的字符

const str = "abcdef";
str.substring(2,4)
'cd'

slice(start, end)方法返回一个索引和另一个索引之间的字符串, 第二个参数为负数, 从串尾部开始计算.

const str = "abcdef";
str.slice(2,5); //'cde'
str.slice(-1, -3); // ''
str.slice(-3,-1); // 'de'
str.slice(-10,9); // 'abcdef'
str.slice(-2,1); // ''
str.slice(-2, -1); // 'e'  相当于 str.slice(4,5)
str.slice(10,20); // ''

【改】替换 replace

replace() 方法用于将指定的字符串正则表达式匹配的部分替换为新的字符串,替换字符串中的第一个匹配项。

const str = "一切 随 风 ";
str.replace(/\s+/g, ""); // '一切随风'

const str = "一切一随一风 ";
str.replace('一', "两"); //'两切一随一风 '

const str = "一切123一随一风 ";
str.replace(/\d+/g, ""); // '一切一随一风 '

正则表达式 /\s+/g 可以匹配所有连续的空格字符。其中,\s 表示空白字符,包括空格、制表符和换行符,+ 表示匹配一个或多个。

【改】替换 replaceAll

replaceAll() 方法是es6中引入的,用于替换字符串中所有匹配的部分。

const str = "一切一随一风 ";
str.replace('一', "两"); // '两切一随一风 '

const str = "一切一随一风 ";
str.replaceAll('一', "两"); // '两切两随两风 '

【查】string.match(regexp)

match 方法用于在一个字符串中查找匹配的子串,并返回一个数组,包含所有匹配的子串及其位置string.match(regexp),其中,string是要匹配的字符串,regexp是一个正则表达式

补充正则表达示规则:

\d:匹配数字字符,等同于[0-9]。

\D:匹配任意非数字字符。

\w:匹配字母、数字或下划线字符,等同于[A-Za-z0-9_]。

\W:匹配任意非单词字符。

\s:匹配空白字符,包括空格、制表符、换行符等。

\S:匹配任意非空白字符。

\b:匹配单词边界。

\B:匹配非单词边界。

[ ]:字符集,匹配方括号中的任意一个字符。

[^ ]:否定字符集,匹配不在方括号中的任意一个字符。
( ):捕获组,用于将匹配到的字符串保存在一个临时变量中,以便后续使用。

{ }:量词,用于描述匹配模式的重复次数。

?:量词,匹配前面的字符或组零次或一次。

+:量词,匹配前面的字符或组一次或多次。

*:量词,匹配前面的字符或组零次或多次。

^:锚点,匹配字符串的开头。

$:锚点,匹配字符串的结尾。
i:忽略大小写。

g:全局匹配。

m:多行匹配。

// 正则表达式/pattern/g可以全局匹配字符串中的所有pattern。

// JavaScript中提供了许多正则表达式的常用方法,包括test、exec、match、replace等.


const str = " abc123你我他 ";
str.match(/\w/g); // ['a', 'b', 'c', '1', '2', '3']

const str = " abc123你我他 ";
str.match(/\d/g); //  ['1', '2', '3']

const str = " abc123你我他 ";
str.match(/\W/g); //  [' ', '你', '我', '他', ' ']

const str = " abc123你我他 ";
str.match(/\D/g); //  [' ', 'a', 'b', 'c', '你', '我', '他', ' ']

const str = " aaaAbc123你我他 ";
str.match(/(2)/g); // ['2']

【查】 search

search方法用于在一个字符串中查找匹配的子串,并返回第一个匹配的子串的位置。它可以接受一个参数,用于指定要查找的子串。找不到匹配的子串则返回-1.


const str = "aaa  Abc 123  你我他";
str.search(/A/); // 5
const str = "aaa  Abc 123  你我他";
str.search(/p/); // -1

【查】includes indexOf lastIndexOf 都区分大小写

includes方法用于检查数组中是否包含某个元素,如果包含则返回 true,否则返回 false。includes()方法区分大小写

indexOf方法只会返回第一个匹配项的位置。

lastIndexOf()方法与indexOf()方法类似,不同之处在于它返回指定字符串或字符在原字符串中最后一次出现的位置,而不是第一次出现的位置

var string1 = "abc";
string1.includes('a'); // true
string1.indexOf('b'); // 1
string1.lastIndexOf('b'); // 1

【查】startsWith endsWith

startsWith() 方法用于判断一个字符串是否以指定的子字符串开头。 endsWith() 方法用于判断一个字符串是否以指定的子字符串结尾。第一个参数是要查找的子字符串,第二个参数是查找的终止位置。当省略第二个参数时,默认从结尾开始查找

var string1 = "abc";
string1.startsWith('a'); // true
string1.startsWith('a',3); // false
string1.endsWith('c',-1); // false
string1.endsWith('c',4); // true
string1.endsWith('c'); // true

【查】 toString

toString()方法返回一个对象的字符串形式。对于自定义对象,如果没有为其定义toString()方法,会使用默认的 toString() 实现,即返回 “[Object object]” 字符串。

var num =1;
var str = 'abc';
var obj = {a:1,b:2};
var arr= [1,2,3];
num.toString(); // '1'
str.toString(); // 'abc'
obj.toString(); // '[object Object]'
arr.toString(); // '1,2,3'

【查】 at charAt

相同点:  都是接收一个数值参数,然后返回一个该字符串数值参数下标的字符

var strs = "a1中国人bc";
strs.charAt(3); // '国'
strs.at(3); // '国'

【查】 codePointAt charCodeAt 传入索引,返回 Unicode 不常用

codePointAt()方法返回指定索引位置处的字符Unicode 编码

charCodeAt()方法可返回指定位置的字符的 Unicode 编码,返回值是 0 - 65535 之间的整数

var strs = "a1中国人bc";
strs.charCodeAt(0); // 97
strs.charCodeAt(3); // 22269
strs.codePointAt(0); // 97
strs.codePointAt(3); // 22269

【查】valueOf 不常用

valueOf()方法返回字符串对象的原始值

valueOf()方法返回一个对象的原始值。如果对象本身就是一个原始值(如数字、字符串、布尔值),则直接返回该值;否则,返回对象本身。

var num =1;
var str = 'abc';
var obj = {a:1,b:2};
var arr= [1,2,3];

num.valueOf(); // 1
str.valueOf(); // 'abc'
obj.valueOf(); // {a: 1, b: 2}
arr.valueOf(); // [1, 2, 3]

【改】normalize 不常用

normalize()用于将字符串标准化为一致的Unicode形式。因为在Unicode中,同样的字符可以有多种不同的表示方式,这可能会导致某些比较或排序操作的混淆。normalize() 方法可以将这些不同表示方式的字符转换为一致的形式,以便在比较和排序等操作中得到正确的结果。

normalize() 方法接受一个参数,表示需要使用哪种标准化形式,共有四种:

1.  NFC:使用组合字符标准化形式。
1.  NFD:使用分解字符标准化形式。
1.  NFKC:使用组合字符同时兼容性标准化形式。
1.  NFKD:使用分解字符同时兼容性标准化形式。

【改】 repeat

repeat() 方法用于将字符串重复指定的次数,并返回重复后的字符串。

const str = 'aBCde'

str.repeat(-2); // 报错
str.repeat(0); // ''
str.repeat(1); // 'aBCde'
str.repeat(2); // 'aBCdeaBCde'

【改】 toUpperCase toLowerCase toLocaleLowerCase toLocaleUpperCase

const str = 'aBCde';
str.toLocaleLowerCase(); // 'abcde'
str.toLowerCase(); // 'abcde'
str.toUpperCase(); // 'ABCDE'
str.toLocaleUpperCase(); //'ABCDE'

将字符串中的所有字母转换为大写字母,同时根据本地化规则将字符转换为特定于语言和区域设置的大小写形式

// 希腊语字符示例:
const str = 'Γειά σου';
console.log(str.toLocaleUpperCase()); // ΓΕΙΆ ΣΟΥ

【改】 trim 去除前后空格


const str = " abc  ";
str.trim(); // 'abc'

str.trimStart(); // 'abc  '
str.trimEnd(); //' abc'
str.trimLeft(); // 'abc  '
str.trimRight(); //' abc'

字符串的转换

【改】 split (切开/劈开); str(可传入reg) => [str, str, ..]

split() 方法使用指定的分隔符字符串将一个字符串分割成字符串数组

const str = "aaa  Abc 123  你我他";
str.split(/\s+/); // ['aaa', 'Abc', '123', '你我他']

URL 字符串处理,是多次通过指定字符串切开字符串

  • 1, 第一次通过'?'切开成两份字符串,得到一个字符串数组
  • 2, 第二次通过 '&' 符号切开成 多份 类似'a=1' 的参数字符串数组
  • 3, 最后,遍历此数组,转换为对象,方便使用.

url 处理

转换过程: str -> arr -> obj


function urlToObj(str){
    if(typeof str !== 'string') { return false;};
    var obj = {};
    str.split('?')[1].split('&').forEach((item,index) => {// 或者map 只有返回值不一样
    
    var res = item.split('=');
    obj[res[0]] = res[1];
    
});
   return obj;
    
}
var str = 'https://juejin.cn/editor/drafts/7323948056264982580?a=1&b=2&c=aaaa';

urlToObj(str);

// {a: '1', b: '2', c: 'aaaa'}

【改】 JSON.stringify obj -> JSON str

JSON.stringify()是JavaScript中的一个方法,用于将JavaScript对象转换为JSON字符串。该方法接受一个JavaScript对象作为参数,并返回一个JSON字符串

语法:`JSON.stringify(value, replace, space)`

1.  value是要转换为JSON字符串的JavaScript对象;
2.  replace是一个函数,用于控制转换过程中哪些属性应该被包含在JSON字符串中;
3.  space是一个用于缩进输出的空格数或缩进字符串。

const obj={
    a:1,
    b:2,
    c:3
}
JSON.stringify(obj); // '{"a":1,"b":2,"c":3}'
JSON.stringify(obj,['a','b']); // '{"a":1,"b":2}'

JSON.stringify(obj,null,2); // '{\n  "a": 1,\n  "b": 2,\n  "c": 3\n}'

字符串汇总

常用方法 split slice substring match replace/replaceAll includes concat/+ trim JSON.stringify toUpperCase toLowerCase

不常用方法 substr search valueOf lastIndexOf indexOf startsWith endsWith normalize repeat localeCompare toLocaleUpperCase toLocaleLowerCase toString charAt at codePointAt charCodeAt

Array 数组

在前端开发中,数组是一种常见且重要的数据结构。数组提供了许多便捷的方法来操作和处理其中的数据。本文将简单介绍前端中数组常用的API,包括添加、删除、截取、合并、转换等操作。

数组的 增删改查

增删改查 包括 push pop unshift shift slice splice concat

push pop unshift shift 数组尾部/头部 进行 添加/删除; 会改变原始数据 , 返回值不好用. 添加是返回修改后的数组的新长度;删除是返回删除的数据

【改】push() 方法和 pop() 方法

尾部删除和插入


let arr11 = ['a', 'b'];
let res = arr11.pop();

console.log(res);   // 'b'
console.log(arr11);   // ['a']

let arr11 = ['a', 'b'];
let res = arr11.push('e');

console.log(res);   // 3
console.log(arr11); // ['a', 'b', 'e']

【改】shift() 方法和 unshift() 方法

头部删除和插入

let arr11 = ['a', 'b'];
let res = arr11.shift();
console.log(res);   // 'a'
console.log(arr11); // ['b']
let arr11 = ['a', 'b'];
let res = arr11.unshift('e');

console.log(res);   // 3
console.log(arr11); // ['e', 'a', 'b']

【改】slice(start, end) 好用, 不改变原始数据

slice() 方法用于从数组中截取指定位置的元素,返回一个新的数组。

array.slice(start, end),其中,startend都是可选参数,表示选取的元素的起始位置和结束位置。如果不传入参数则默认选取整个数组。该方法返回的是一个新的数组,包含从startend不包括end)的元素。

var arr1 = ['a','b', 1,2,3]
arr1.slice(1,3) //  ['b', 1]
arr1.slice(1) // ['b', 1, 2, 3]
var arr1 = ['a','b', 1,2,3]
arr1.slice(3) // [2, 3]
arr1 // ['a', 'b', 1, 2, 3]

【改】splice 删除、替换或添加, 会直接修改原数组

功能决定必须改变原数组,并不是改变原数组就不好.

splice() 方法用于从数组中删除、替换或添加元素,并返回被删除的元素组成的数组,它会直接修改原数组

语法:array.splice(start, deleteCount, item1, item2, ...)

其中,start表示要修改的起始位置,deleteCount表示要删除的元素个数,item1、item2等表示要添加的元素。如果deleteCount为0,则表示只添加元素,不删除元素。

var arr1 = ['a','b', 1,2,3]
arr1.splice(2,2) // [1, 2] 返回删除的元素组成的数组
console.log(arr1); // ['a', 'b', 3] 改变原数组
var arr1 = ['a','b', 1,2,3]
arr1.splice(2,2,8, 9); // [1, 2] 返回删除的元素组成的数组
console.log(arr1); //  ['a', 'b', 8, 9, 3]; 改变原数组

【改】concat , 不改变原始数据

concat() 方法用于合并两个或多个数组,返回一个新的数组。

var arr1 = ['a','b']
var arr2 = [['c'],'d']
var arr3= arr1.concat(arr2)

console.log(arr3); //['a', 'b', Array(1), 'd']

通过扩展运算符连接数组

var arr1 = ['a','b'];
var arr2 = ['c','d'];
function concatArr(arr1, arr2){
 return [...arr1, ...arr2]
}
concatArr(arr1, arr2); // ['a', 'b', 'c', 'd']

转换相关

【改】 join 转字符串 能传入参数(间隔符)

join() 方法用于将数组中的所有元素以指定的分隔符连接成一个字符串


var arr = ['a','b',1]

var b = arr.join('-')
// 'a-b-1'

不改变输出数据,数组铺平后转成字符串

var arr = [1,2,3,4,5, ['a',['b']],'c']

var b = arr.join(',')

// 输出 b :  '1,2,3,4,5,a,b,c'
// 输出 arr :  [1,2,3,4,5, ['a',['b']],'c']

【改】 toString 转字符串 不能传入参数(间隔符)

toString方法将数组转换为一个由数组元素组成的字符串,元素之间用逗号分隔。

因为不能传入参数(间隔符), 不好用, 不如用 join

var arr1 = ['a','b']
arr1.toString()
// 'a,b'

遍历相关

for , for..of , for..in(遍历对象用) , forEach (高频), map(高频), filter , reduce(不常用)

1. for , for..of , for..in

for in遍历的是数组的索引(键名),而for of遍历的是数组元素值。 所以for in更适合遍历对象,不要使用for in遍历数组。

for

for循环中,可以用break终止全部循环,用continue跳出一层循环, 其他方法通过 if + return 的方式跳出循环.

var array = [1, 2, 3, 4, 5];
for (var i=0; i< array.length; i++) {
  console.log(array[i]);
}
// 1 2 3 4 5

for(语句 1; 语句 2; 语句 3){} :for 循环是 Js 中最常用的一个遍历方式,经常用于数组的循环遍历,可以遍历字符串、数组、类数组对象 , 但不可以遍历对象

for..in 遍历对象用 遍历的是索引

使用for in 也可以遍历数组,但是会存在以下问题:

1.index索引为字符串型数字,不能直接进行几何运算

2.遍历顺序有可能不是按照实际数组的内部顺序

3.使用for in会遍历数组所有的可枚举属性,包括原型。

不要用 for in 遍历数组


var array = [8, 9, 10];
for (var item in array) {
  console.log(array[item]);
}
// 8 9 10 
var obj={a:1,b:2};
Object.prototype.cc = [2,6]
for (var item in obj) {
  console.log(item);
}
//a b cc

for..of 遍历的是元素

一般用于遍历数组,不可遍历对象

var array = [8, 9, 10];
for (var item in array) {
  console.log(item);
}
// 8 9 10 
var obj={a:1,b:2};
Object.prototype.cc = [2,6]
for (var item of obj) {
  console.log(item);
}
// Uncaught TypeError: obj is not iterable

2. forEachmapfilterreduce

forEach() 方法用于对数组中的每个元素执行一个回调函数. 没有返回值.

map() 方法用于对数组中的每个元素执行一个回调函数,并返回一个新的数组,新数组中的元素为回调函数的返回值。

注意: 1. 箭头函数多行时,不要忘记加上 return; 2, 注意边界处理, 入参类型判断. 3, 一个函数: 一是输入,一是输出,把握好这两个.中间转换处理数据即可. 4. 注意, JS 原生方法有的有返回值,有的没有,有的改变原始数据,有的不改变.用好用的就好,一般都会封装自己的类库/工具库.


function urlToObj(str){
    if(typeof str !== 'string') { return false;};
    var obj = {};
    str.split('?')[1].split('&').forEach((item,index) => {// 或者map 只有返回值不一样
    
    var res = item.split('=');
    obj[res[0]] = res[1];
    
});
   return obj;
    
}
var str = 'https://juejin.cn/editor/drafts/7323948056264982580?a=1&b=2&c=aaaa';

urlToObj(str);

// {a: '1', b: '2', c: 'aaaa'}

map 和 forEach 的回调函数中的参数是一样的都是三个: item,index,arr, 当前元素,索引,原始输入数组.


const numbers = [1, 2, 3, 4, 5];
const addNumbers = numbers.map((item, index, arr)  => {
     // console.log(item, index, arr);
    return item + 1;
});

console.log(addNumbers); // [2, 3, 4, 5, 6]

filter

filter() 方法用于筛选、过滤数组中符合条件的元素,并返回一个新的数组。

var arr = [1,2,3,4,5];
var initVal = 100;
arr.filter((item,index,arr)=>{
    return item > 2;
});
// [3, 4, 5]

reduce

reduce() 方法是数组对象的一个方法,用于将数组中的所有元素按照指定的规则进行归并计算,返回一个最终值。

语法:array.reduce(callback, initialValue)

该方法接收两个参数,第一个参数是一个回调函数,第二个参数是一个初始值。回调函数中可以接收四个参数,分别是:

  1. accumulator:累加器,用于存储上一次回调函数的返回值或初始值。
  2. currentValue:当前元素的值。
  3. currentIndex:当前元素的索引。
  4. array:数组对象本身。

initialValue 是初始值,可选参数

var arr = [1,2,3,4,5];
var initVal = 100;
arr.reduce((acc,item,index,arr)=>{
    return acc+item;
},initVal)
// 115

数组查找

includes(高频) , indexOf(高频) , lastIndexOf , findIndex

includes [] -> boolean布尔值

includes方法用于检查数组中是否包含某个元素,如果包含则返回 true,否则返回 false。

与 indexOf() 方法不同,includes() 方法不支持指定起始位置,它从数组的开头开始搜索

var arr1 = ['a','b', 'b', 'c', 'b'];
arr1.includes('b');// true
arr1.includes(1);// false

indexOf [] -> Number索引值或-1

需要注意的是,indexOf方法只会返回第一个匹配项的位置。如果数组中存在多个相同的元素,该方法只会返回第一个元素的位置。

此外,indexOf方法还可以接受一个可选的第二个参数,用于指定从哪个位置开始查找

var arr1 = ['a','b', 'b', 'c', 'b'];
arr1.indexOf('b'); //1 
var arr1 = ['a','b', 'b', 'c', 'b'];
arr1.indexOf('b',3); // 4
arr1.indexOf('c',6); // -1

lastIndexOf [] -> Number索引值或-1

lastIndexOf() 方法用于查找数组中某个元素最后一次出现的索引(位置),如果找到则返回该索引值,否则返回 -1。

var arr1 = ['a','b', 'b', 'c', 'b'];
arr1.lastIndexOf('b'); // 4

findIndex [](cb) -> Number索引值或-1

findIndex() 方法用于查找数组中满足条件的元素的索引,如果找到则返回该索引值,否则返回 -1。

var arr1 = ['a','b', 'b', 'c', 'b'];
arr1.findIndex((item)=>{ 
    return item === 'c'
})
// 3 

数组排序

reverse

reverse() 方法用于反转数组中的元素顺序,即将数组元素进行逆序排列。

const arr = [1, 2, 3, 4, 5];
arr.reverse();
console.log(arr); //[ 5, 4, 3, 2, 1 ]

数组不常用方法

fill填充方法 , Array.from , toString ,toLocaleString

fill 改变原数据

JS中的fill方法可以填充一个数组中的所有元素,它会直接修改原数组。

array.fill(value, start, end)

value表示要填充的值,start和end表示要填充的起始位置和结束位置。如果不传入start和end,则默认填充整个数组。该方法返回的是被修改后的原数组。

var arr = [1,2,3,4,5];
arr.fill(9); // fill返回数组 [9, 9, 9, 9, 9]
console.log(arr); // [9, 9, 9, 9, 9] 原数组被改变

Array.from

结合 new Set 数组去重

var arr = [1,2,1,3,1,2,3,4,5];
Array.from(new Set(arr))
//[1, 2, 3, 4, 5]
var arr1 = [...new Set(arr)]
// [1, 2, 3, 4, 5]

toString

toString 方法将数组转换为一个由数组元素组成的字符串,元素之间用逗号分隔。

var arr1 = ['a','b']
arr1.toString()
// 'a,b'

toLocaleString

toLocaleString方法将数组转换为一个由数组元素组成的字符串,元素之间同样用逗号分隔,但是它会根据当前环境的语言和地区设置来决定元素的格式。

Array.from str -> []

Array.from() 是 JavaScript 中一个用于从类数组或可迭代对象创建新数组的静态方法。它接收一个可迭代对象或类数组的对象,并返回一个新的数组实例

//使用字符串创建数组
var str1 = "abc";
var arr1 = Array.from(str1);
console.log(arr1); // ['a', 'b', 'c']

2.3 前后端交互

JQ 封装的ajax, vue 封装的 axios, 底层都是通过创建一个 XML 对象来发请求,获取处理数据的

三 vue 常用方法

  1. vue 2.0 MVVM 的观察者模式 数据和DOM 之间 的联动更新.
  2. vue 3.0 增加了一些新的规则,优化了写法,和机制. 其源码必然也是要进行大量调整, 比如语法树的处理规则调整

四 webpack 常用方法

五 node 常用方法

CommonJS 就是模块化的标准,Node.js 就是 CommonJS(模块化)的实现。

用了 node 哪些功能

  1. 本地启动服务,不在依赖后端来看开发效果.
  2. mock 数据, 接口没有开发完成时,把数据请求和处理写好
  3. npm 包, 各种工具包, 尤其是 vue 火了之后, vue文件的编译, 各种loader ,插件来处理代码,最终生成浏览器可识别的 html css js

node 常用 API

  1. fs 模块 (file system ) 文件的增删改查
  2. path 模块 文件路径处理
  3. http 模块 1: 监听端口, 本地可以调试了; 2: 创建服务 区分请求地址,请求方式和参数, 设置响应头,响应内容. 保持服务是启动状态,可以进行调用
  4. url 模块 获取地址,参数等信息
  5. npm模块 第三方模块
  6. process 模块 Node.js 中的进程 Process 是一个全局对象,无需 require 直接使用,给我们提供了当前进程中的相关信息 process.cwd():获取当前进程工作目录; process.env:环境变量,例如通过 process.env.NODE_ENV 获取不同环境项目配置信息
  7. child_process 模块和 cluster 模块

node 进程守护 pm2

每次启动 Node.js 程序都需要在命令窗口输入命令 node app.js 才能启动,但如果把命令窗口关闭则Node.js 程序服务就会立刻断掉. 这个时候就可以用 pm2, 比较简单,底层也都是通过 child_process 模块和 cluster 模块 实现的,这里就不再提它们的原理。

单线程的一些说明

  • Node.js 虽然是单线程模型,但是其基于事件驱动、异步非阻塞模式,可以应用于高并发场景,避免了线程创建、线程之间上下文切换所产生的资源开销。
  • 当你的项目中需要有大量计算,CPU 耗时的操作时候,要注意考虑开启多进程来完成了。
  • Node.js 开发过程中,错误会引起整个应用退出,应用的健壮性值得考验,尤其是错误的异常抛出,以及进程守护是必须要做的。
  • 单线程无法利用多核CPU,但是后来Node.js 提供的API以及一些第三方工具相应都得到了解决,文章后面都会讲到。
  • 在单核 CPU 系统之上我们采用 单进程 + 单线程 的模式来开发。在多核 CPU 系统之上,可以通过 child_process.fork 开启多个进程(Node.js 在 v0.8 版本之后新增了Cluster 来实现多进程架构) ,即 多进程 + 单线程 模式。注意:开启多进程不是为了解决高并发,主要是解决了单进程模式下 Node.js CPU 利用率不足的情况,充分利用多核 CPU 的性能。

六 JS 高频面试题汇总

1. JS 运行机制 单线程异步 任务队列(同步任务,异步任务) 事件循环(Event loop)

同步任务(注意: 包括 while )执行完之前, 任何异步任务不会执行的 异步任务包括 setTimeout setInterval DOM事件 ES6中的Promise

注意: 同步任务和异步任务的优先关系, 异步任务队列被 放入的时间执行时间

浏览器卡了的时候, 有可能就是同步任务没有执行完, 所以不会响应异步任务,点击等操作没有反应.

// 异步队列被放入的时间和执行时间; 异步队列里并没有东西, 因为先执行完for, 然后才执行setTimeout
for(var i =0; i<4; i++){
    setTimeout(function(){
        console.log(i);
    }, 1000);// 延迟0秒,也是 输出 4 个 4
}
// 输出 4 个 4. 是因为setTimeout 中的代码并未放到异步任务队列中,执行的时候,for 循环已经运行完了.

2. 数组去重

3. 数组铺平 - 栈的方式 | 递归 | 遍历

4. 对象遍历的7种方法

5. 深拷贝

6. new的实现

7. ajax的实现

8. 柯里化实现

9. 闭包应用

10. 手写一个 promise

11. vue 源码解读

12. vue diff 算法

13. 手写一个 webpack

14. 手写一个脚手架

15. 手写一个组件库

16. 设计模式

17. 手写一个订阅发布模式

18. JS的执行顺序(事件循环EventLoop)同步/异步任务 宏/微任务

19. 语法树的解析处理生成

20. ( 冒泡 | 快速 | 归并 ) 排序

21. 【JS基础-优化】节流与防抖简易版

22. 【JS引擎】解析过程

23. node 中进程与线程

24. 数据类型: 值类型 与 引用类型(指针)

25. 浏览器缓存

强缓存协商缓存

26. 错误监控类(保证产品质量)

错误分类, 错误捕获方式, 上报错误的基本原理

前端错误分类:

一 即时运行错误(代码错误)捕获方式: 1) try...catch 2) window.onerrer(或者window.addEventListener)

能被 try catch 捕捉到的异常,必须是在报错的时候,线程执行已经进入 try catch 代码块,且处在 try catch 里面,这个时候才能被捕捉到。 如果是在之前,或者之后,都无法捕捉异常。比如,代码块中是 setTimeout 或者promise 在执行 setTimeout 时 , try catch 已经执行完.

try{  
    a.  
}catch(e){  
    console.log("error",e);  
}  
// Uncaught SyntaxError: Unexpected token '}'

二 资源加载错误: 捕获方式: 1) object.onerrer(比如图片,script标签等都有onerrer事件) 2) performance.getEntries() 3)Error 事件捕获

注意: 资源加载错误不会冒泡, 只触发本身的 onerrer , 不会上报到 window.onerrer

// 获取页面中加载的所有资源的name
performance.getEntries().forEach(item => console.log(item.name))
// 注意: 第三个参数是 true 是捕获,是 false 是冒泡
// 比如加载了一个不存在的JS文件,错误会被捕获, 冒泡是不行的.
window.addEventListener('error', function(e){
  console.log('捕获',e)
}, true)

上报错误的基本原理

  1. 采用 Ajax 通信的方式上报
  2. 采用 Image 对象上报 ( SDK 常用)
// 不借助任务库和辅助函数,一行代码搞定
(new Image()).src = 'http://xx.com/aa?a=1'

27. 前端入门

页面布局 与 两种 CSS 盒模型 与 BFC块级格式化上下文(边距重叠解决方案) , IFC, FFC, GFC

页面布局 左右各100px, 中间自适应

几种方法: 1. 浮动 2. 绝对定位 中间left:100px; right:100px; 自动撑起 3. flex布局 display:flex 中间flex:1 撑起来 4. 网格grid布局 display: grid 5. 表格布局 display:table

标准模型IE模型 的区别 (计算高度宽度的不同)

标准模型宽高不算padding和border . IE模型是计算的.

box-sizing: content-box; // 标准模型 浏览器默认的方式
box-sizing: border-box; // IE 模型

边距重叠的三种场景

  1. 父子之间
  2. 兄弟元素之间
  3. 与设置了margin的空元素

margin 取了大的值.

BFC块级格式化上下文 (边距重叠解决方案: 设置BFC)

1. 设置 float 不为默认值, BFC元素不与float元素重叠
2. 设置定位 不为默认值
3. 设置 overflow: hidden/auto;

JS获取盒模型的宽和高

// JS获取盒模型的宽和高
dom.style.width/height // 获取不了外链样式的宽高
dom.currentStyle.width/height // 只有IE支持
window.getComputedStyle(dom).width/height // 兼容性好
dom.getBoundingClientRect().width/height // 兼容性好

DOM事件模型 ( 注册事件 捕获/冒泡 自定义事件 )

事件级别

// DOM0 
element.onclick= function(){}
// DOM2
element.addEventListener('click', function(){}, false)
// DOM3 只是增加了鼠标事件,键盘事件等
element.addEventListener('keyup', function(){}, false)

事件流

捕获/冒泡

面向对象

原型链

HTTP/HTTPS 协议

通信

跨域通信 jsonp(动态创建 script) cros 与 前后端通信

安全

csrf xss

算法

考验的是, 对于 JS 方法的熟练运用程度, 和解决问题的思路.

能力一般,水平有限,本文可能存在纰漏或错误,如有问题欢迎指正,感谢你阅读这篇文章,如果你觉得写得还行的话,不要忘记点赞、评论、收藏哦!祝生活愉快!