项目中遇到的数组遍历问题?
forEach方法
forEach是JavaScript中数组的一个函数方法,可以对数组中的每个元素执行一个指定的函数。forEach循环会自动迭代数组,对每个元素执行回调函数,并跳过数组中未定义的元素。
forEach方法的语法如下:
c
array.forEach(function(currentValue, index, array) {
// 执行内容
}, thisValue);
其中,第一个参数是回调函数,它可以接受三个参数:当前处理的元素值currentValue、当前处理的元素索引index、当前正在操作的数组对象array。第二个参数thisValue可选,表示在执行回调函数时,将其作为函数体内this关键字的值。
例如,我们可以使用forEach方法遍历数组并输出每个元素:
ini
var array = [1, 2, 3, 4, 5];
array.forEach(function(element) {
console.log(element);
});
- 返回值:
undefined
- 是否改变原数组:
可以改变原数组
- 使用时机:
用于对数组中的每个元素执行指定的操作
特性:
- 除非抛出异常,否则没有办法停止或中断,不能使用break 会报错
- 不可以直接修改元素,但是可以修改元素的属性
filter方法
filter() 是 JavaScript 数组的一个内置函数方法,用于筛选数组中满足指定条件的元素,并返回一个新的数组。它不会修改原始数组,而是返回一个新的数组,新数组中包含满足筛选条件的元素。
filter() 方法的语法如下:
c
array.filter(function(currentValue, index, array) {
// 指定条件判断
}, thisValue);
第一个参数是回调函数,它可以接受三个参数:当前处理的元素值currentValue、当前处理的元素索引index、当前正在操作的数组对象array。第二个参数thisValue可选,表示在执行回调函数时,将其作为函数体内this关键字的值。
例如,我们可以使用 filter() 方法筛选出数组中大于等于5的元素:
ini
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var filteredNumbers = numbers.filter(function(num) {
return num >= 5;
});
console.log(filteredNumbers); // [5, 6, 7, 8, 9, 10]
这里的回调函数只有一个参数num,表示当前处理的元素值,它会被依次传入数组中的每个元素。回调函数中的判断条件return num >= 5
表示只有当元素大于等于5时,返回true,才会保留在新数组中。
需要注意的是,filter() 方法会返回一个新数组,而不是修改原有数组。它也不会修改原有数组中的元素。如果没有满足条件的元素,返回的新数组将为空数组。
- 是否改变原数组:
不改变原数组
- 返回值:
[]|[...ele]
- 使用时机: 用于根据指定的条件筛选出数组中满足条件的元素
特性:
- 除非抛出异常,否则没有办法停止或中断,不能使用break 会报错
- 筛选掉不符合条件的元素,返回符合条件的元素
reduce方法
reduce() 是 JavaScript 数组的一个内置函数方法,用于对数组中的元素进行累积操作,将数组缩减为一个值。它通过提供的回调函数来实现累积操作,并返回最终结果。
reduce() 方法的语法如下:
c
array.reduce(function(accumulator, currentValue, index, array) {
// 累积操作
}, initialValue);
第一个参数是回调函数,它可以接受四个参数:累积器(accumulator)、当前处理的元素值(currentValue)、当前处理元素的索引(index)和当前正在操作的数组对象(array)。第二个参数initialValue可选,表示初始的累积值。
例如,我们可以使用 reduce() 方法对数组中的元素求和:
ini
var numbers = [1, 2, 3, 4, 5];
var sum = numbers.reduce(function(total, num) {
return total + num;
}, 0);
console.log(sum); // 15
这里的回调函数接受两个参数total和num,total表示累积值,初始值为0,而num表示当前处理的元素值。在每一次迭代中,回调函数会将total与当前元素值num相加,然后返回新的累积值。最终,reduce() 方法返回的是最后一次迭代后的累积值。
需要注意的是,如果没有提供初始值(initialValue),那么数组的第一个元素将作为初始的累积值,并从数组的第二个元素开始进行迭代。如果数组为空且没有提供初始值,那么将抛出 TypeError 异常。
some方法
- 参数: some(callbackFn[, thisArg]),接受一个回调函数作为参数,回调函数可以接受三个参数:
element
正在处理的当前元素。、index
当前元素的索引、array
被遍历的数组。 - 返回值:
true|false
- 是否改变原数组:
不改变原数组
- 使用时机: 用于检查数组中是否至少存在一个元素满足指定的条件
特性:
- 除非抛出异常或者返回
true
,否则没有办法停止或中断,不能使用break 会报错 - 如果有一个元素符合条件,则循环不再继续,直接返回
true
,否则返回false
ini
const numbers = [1, 2, 3, -4, 5];
const hasNegative = numbers.some(num => num < 0);
console.log(hasNegative);
every方法
- 参数: every(callbackFn[, thisArg]),接受一个回调函数作为参数,回调函数可以接受三个参数:
element
正在处理的当前元素。、index
当前元素的索引、array
被遍历的数组。 - 返回值:
true|false
- 是否改变原数组:
不改变原数组
- 使用时机: 用于检查数组中的所有元素是否都满足指定的条件
特性:
- 除非抛出异常或者返回
false
,否则没有办法停止或中断,不能使用break 会报错 - 如果有一个元素不 符合条件,则循环不再继续,直接返回
false
,否则返回true
ini
// 必须都满足才返回true,否则立刻终止循环
const numbers = [1, 2, 3, 4, 5];
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true
// 数组排序判断:在对数组进行排序或筛选时,可以使用 `every` 方法进行判断。
// 例如,检查数组是否已按升序排序。
const sortedNumbers = [1, 2, 3, 4, 5];
const isSortedAscending = sortedNumbers.every((num, index, arr) => {
if (index === 0) {
return true;
}
return num >= arr[index - 1];
});
console.log(isSortedAscending); // true
some
和 every
刚好相反
some
只要有一个符合条件的就返回 trueevery
必须全部满足条件才返回 true
map方法
- 参数: map(callbackFn[, thisArg]),接受一个回调函数作为参数,回调函数可以接受三个参数:
element
正在处理的当前元素。、index
当前元素的索引、array
被遍历的数组。 - 返回值:
返回一个新数组,该数组由回调函数的返回值组成。
- 是否改变原数组:
不改变原数组
- 使用时机: 返回的数据不符合我们的要求,可以使用 map 把数据处理成我们想要的
ini
const fruits = ['apple', 'banana', 'orange'];
const capitalizedFruits = fruits.map(fruit => fruit.toUpperCase());
console.log(capitalizedFruits); // ['APPLE', 'BANANA', 'ORANGE']
特性:
- 数组长度保持一致:新数组的长度与原数组相同,每个元素对应原数组中的一个元素。新数组元素受返回值影响
- 除非抛出异常,否则没有办法停止或中断,不能使用break 会报错
find方法
参数: find(callbackFn[, thisArg]),接受一个回调函数作为参数,回调函数可以接受三个参数:element
正在处理的当前元素。、index
当前元素的索引、array
被遍历的数组。
返回值: undefined|符合条件的元素
是否改变原数组: 不改变原数组
使用时机: 用于在数组中查找满足指定条件的第一个元素
特性:
- 除非抛出异常或者找到
符合条件的元素
,否则没有办法停止或中断,不能使用break 会报错 - 找到第一个符合条件的元素返回并中断循环,否则所有元素都循环一遍,返回undefined
ini
const numbers = [1, 2, 3, -4, 5];
const negativeNumber = numbers.find(num => num < 0);
console.log(negativeNumber); // -4
const users = [
{ name: 'John', age: 25 },
{ name: 'Jane', age: 18 },
{ name: 'Bob', age: 30 }
];
const user = users.find(user => user.name === '张三');
console.log(user); // undefined
filter
和 find
的区别:
- 返回值:
- filter函数:返回一个由满足条件的元素组成的新数组,如果没有元素满足条件,则返回空数组。
- find函数:返回满足条件的第一个元素,如果没有找到满足条件的元素,则返回undefined。
- 用途:
- filter函数:用于筛选出数组中符合条件的元素,并返回一个新数组。适用于需要筛选多个元素的情况。
- find函数:用于查找数组中满足条件的第一个元素,并返回该元素。适用于查找单个元素的情况。
总结:
- 特定的循环,并且需要中断和跳过可使用
for
- 无需返回值可使用
forEach
- 检查是否满足指定条件而无需使用元素可使用
some、every
- 筛选符合条件的元素可使用
filter、find
- 需要对不符合展示条件的数据继续再处理时可使用
map
- 需要依赖数组元素上次结果,如累计可使用
reduce
js中的try...catch
捕获所有异常
如果你想捕获代码中所有可能的异常,可以使用一个不带参数的 catch
代码块。例如:
arduino
try {
// 可能会抛出异常的代码
} catch {
// 处理所有异常的代码
}
这种方式会捕获所有异常,包括语法错误 、运行时错误 和自定义错误。但是,在生产环境中使用时,建议具体指定要捕获的异常类型,以便更好地诊断问题。
捕获特定类型的异常
如果你只想捕获特定类型的异常,可以在 catch
代码块中使用条件语句。例如,以下代码块只会捕获 TypeError
异常:
javascript
try {
// 可能会抛出 TypeError 异常的代码
} catch (error) {
if (error instanceof TypeError) {
// 处理 TypeError 异常的代码
}
}
也可以使用 switch
语句来检查异常类型:
javascript
try {
// 可能会抛出异常的代码
} catch (error) {
switch (error.constructor) {
case TypeError:
// 处理 TypeError 异常的代码
break;
case RangeError:
// 处理 RangeError 异常的代码
break;
// ...
}
}
捕获异步异常
如果你使用了异步代码,你可能需要捕获异步代码中的异常。例如,以下代码块使用 Promise
来异步加载资源:
csharp
try {
const resource = await fetch("/resource");
// 处理资源的代码
} catch (error) {
// 处理异常的代码
}
如果在异步操作中发生异常,它会被传递到 catch
代码块中。但是,如果你没有使用 try...catch
来捕获异常,它将被视为未处理的异常。
在 finally 代码块中清理资源
如果使用了一些需要手动清理的资源(例如网络连接),可以在 finally
代码块中进行清理操作。无论 try
代码块中是否发生异常,finally
代码块中的代码都会执行。例如:
scss
let resource;
try {
resource = acquireResource();
// 处理资源的代码
} catch (error) {
// 处理异常的代码
} finally {
releaseResource(resource);
}
抛出异常
try...catch
不仅可以捕获异常,还可以抛出异常。你可以使用 throw
语句在代码中手动抛出异常。例如:
javascript
function divide(a, b) {
if (b === 0) {
throw new Error("除数不能为零");
}
return a / b;
}
如果在 divide
函数中 b
的值为 0
,则会抛出一个包含错误消息的异常。你可以使用 try...catch
来捕获这个异常并执行相应的操作。
在异常中传递额外信息
在抛出异常时,你可以传递一些额外的信息来帮助调试问题。例如:
css
function divide(a, b) {
if (b === 0) {
throw new Error("除数不能为零", { a, b });
}
return a / b;
}
在这个例子中,异常对象包含了除数为零时的 a
和 b
的值。当你捕获这个异常时,你可以访问这些值并进行相应的操作。
将异常重新抛出
有时,在处理异常时,你需要将异常重新抛出以便于更高层次的代码进行处理。你可以使用 throw
语句来重新抛出异常。例如:
csharp
try {
// 可能会抛出异常的代码
} catch (error) {
// 处理异常的代码
throw error;
}
在这个例子中,异常会被重新抛出并传递到调用函数中进行处理。
捕获错误并忽略它们
有时,在调试代码时,你可能希望暂时忽略一些错误。你可以使用空的 catch
代码块来忽略异常。例如:
arduino
try {
// 可能会抛出异常的代码
} catch {
// 忽略异常
}
使用 Promise.catch 方法
如果你使用 Promise
来处理异步代码,你可以使用 Promise.catch
方法来捕获异常。例如:
typescript
fetch("/resource")
.then((response) => response.json())
.then((data) => {
// 处理数据的代码
})
.catch((error) => {
// 处理异常的代码
});
在这个例子中,如果 fetch
或 json
方法返回异常,它们会被传递到 catch
方法中进行处理。
使用 window.onerror
使用 window.onerror
来全局捕获异常。当页面中发生未处理的异常时,window.onerror
会被调用。你可以在 window.onerror
中记录异常信息,以便于在生产环境中诊断问题。例如:
ini
window.onerror = function handleError(message, source, lineno, colno, error) {
// 记录异常信息
};
css作用域
众所周知,vue的scoped是为了让**css
也有独立的作用域,当前组件写的样式只对当前组件的 template
**生效,而在react中我们该如何让css有独立的作用域呢
现象及原因
在配置路由时,多个组件都被导入到项目中,那么组件的样式也就被导入到项目中了,也就是说最终的所有的样式文件全汇集到index.html中了。
如果多个组件的样式中出现选择器重复,那么一个组件中的样式就会在另一个组件中也生效,从而造成组件之间样式相互覆盖的问题。
了解css in js解决方案
- 手动处理: 给每个组件的根元素起不同的类名,确保类名不重复
- CSS IN JS : 以js的方式来处理css 。通过代码来改动css选择器,让css样式也有局部作用域 全局作用域这样的区分
CSS IN JS
CSS IN JS:是使用 JavaScript 编写 CSS 的统称,用来解决 CSS 样式冲突、覆盖等问题,具体实现有 很多种,比如:CSS Modules、scoped css,等。
在vue中默认使用的是scoped css,
在react中推荐使用:CSS Modulesopen in new window(推荐原因:React脚手架已集成,可直接使用)
CSS Modules 是一种 CSS 编码方法,它允许将 CSS 文件视为 JavaScript 模块。通过使用 CSS Modules,您可以将 CSS 类名和样式局部化,以避免全局样式冲突。CSS Modules 还允许您在 JavaScript 中动态地应用和删除样式。
要在项目中使用 CSS Modules,您需要遵循以下步骤:
- 配置构建工具:如果您使用的是 Webpack,您需要在配置文件中添加一个规则,以便将
.module.css
文件视为 CSS Modules。以下是一个示例配置:
css
module.exports = {
// ...
module: {
rules: [
{
test: /.module.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
},
},
],
},
],
},
};
在这个配置中,我们使用 style-loader
和 css-loader
处理 .module.css
文件。css-loader
的 modules
选项用于配置 CSS Modules。localIdentName
选项用于定义生成的类名的格式。
- 创建 CSS 文件:在项目中创建一个或多个 CSS 文件,并将其扩展名更改为
.module.css
。例如,创建一个名为styles.module.css
的文件,并添加一些样式:
css
.container {
display: flex;
justify-content: center;
align-items: center;
}
.button {
background-color: blue;
color: white;
padding: 10px;
border-radius: 5px;
}
- 在 JavaScript 中导入和使用 CSS 模块:在 JavaScript 文件中,您可以使用
import
语句导入 CSS 模块。导入的对象将包含 CSS 文件中定义的所有类名,您可以将这些类名动态地应用于 HTML 元素。例如:
javascript
import React from 'react';
import styles from './styles.module.css';
function MyComponent() {
return (
<div className={styles.container}>
<button className={styles.button}>Click me</button>
</div>
);
}
export default MyComponent;
在这个示例中,导入了 styles.module.css
文件,并将其应用于一个 React 组件。使用 className
属性将样式动态地应用于 HTML 元素。
前端国际化
一个成功的产品要走向全球需要经历很多环节,从软件开发的视角主要有国际化和本地化两个流程:

语言环境是在某个国家或地域内使用特定的语言或语言变体,其决定了日期、时间、数字和货币的格式和解析方式,以及各种测量单位和时区、语言、国家与地区的翻译名称。国际化使一个软件能够处理多个语言环境,本地化使一个软件支持一个特定的地区的语言环境。这意味着全球化的流程是先使软件具备国际化的能力,之后做本地化实施使其能支持特定地区特定的语言环境。
基于他们的英文单字长度过长,常被分别简称成i18n(18意味着在"internationalization"这个单字中,i和n之间有18个字母)及L10n。使用大写的L以利区分i18n中的i和易于分辨小写l与1。(Wikipedia)
国际化(i18N)
国际化需解决的问题
- 能够以用户本地的语言显示文本;
- 能够以用户本地的语言输入文本;
- 能够处理以特定编码的用户本地语言的文本
国际化相关标准
我们知道国际化是为了解决与用户本地语言相关的文本显示与输入的问题,这个问题又与用户国家和语言相关,比如同样的英语在美国和英国就不同。在国际化标准还未出现之前,曾经有多种表示国家与语言的方法,这个 Making Sense of Language Tags 的Slide就分享了这段有趣的国际化标准问世的历史。直到IETF BCP(Best Current Practice) 47的出现,才统一规定了国际化中语言标识(Language Tag)的定义及匹配标准。
而由于很多软件与系统早于此标准出现,就会出现一些与此标准不统一的问题。一个突出的问题就是语言标识定义中的连接线的选择,在Linux系列的操作系统中用locale来定义语言环境,如en_US
表示美国英语,而在BCP 47中用en-US
表示美国英语。前者选择了用_
而后者采用了-
来连接语言和国家。这种混乱有时候会带来很多意想不到的困惑,有时候你使用的某个库支持en_US
,有的库却支持en-US
,这不得不让国际化实现的过程中多了一些兼容性处理的工作,甚至因为语言不统一,出现很多沟通上的问题。
国际化相关的标准如下:
-
IETF RFC 6365:统一定义了和国际化相关的术语。
-
IETF BCP47
- RFC 4647:制定了如何通过过滤(Filtering)和查找(Lookup)的方式匹配语言标识(Language Tag)。
- RFC 5646:定义了语言标识(Language Tag)的组成,如使用
en-US
标识美国英语。
-
ISO
- ISO 639:语言编码(Language codes)标准。
- ISO 3166:国家编码(Country codes)标准。
- ISO 15924:脚本(Script codes)标准。
一个完整的语言标识(Language Tag)组成如下:

文本编码
不同编码有着可以表示不同字符集合的区别,比如我们无法用ASCII编码来表示汉字。Unicode字符集可以用从0到10FFFF (十六进制)范围的码点来显示几乎所有人类已知的字符。它的存储至少需要21位。文本编码系统UTF-8将Unicode码点适配到一个合理的8位数据流,并兼容ASCII数据处理系统。UTF表示Unicode转换格式(Unicode Transformation Format)。
自2009年以来,UTF-8一直是万维网的最主要的编码形式。截止到2019年11月, 在所有网页中,UTF-8编码应用率高达94.3%(其中一些仅是ASCII编码,因为它是UTF-8的子集),而在排名最高的1000个网页中占96%。所以在国际化中推荐采用UTF-8编码。
一些GBK编码的文本中有许多"看起来一样"的文字,其实有细微差别。但是,为了节省Unicode中的空间,给它们指定了同样的Code Point。

如何区分这些同样码位(用不同字形显示一个字符,即同一字位)的同位异字?这就需要locale的帮助了。
计算汉字数量时,通常是按照字形来计算的,即将一个代表相同语音语义的字的简化,繁体,异体,新字形,旧字形等等分别进行计算。这种计算方式实为是在计算变体。所以,长期以来错误地把大型字典里收入的字形数看作是汉字系统的规模。(Wikipedia)
locale与language tag
locale是软件在运行时的语言环境,它包括语言(Language),地域(Territory)和字符集(Codeset)。locale使用language tag标识语言国家,比如在GNU Linux中的定义格式为:语言[_地域[.字符集]],如美国英文是en_US.UTF8
。在Linux中locale包括以下几个部分:
LC_COLLATE:控制字符排序。
LC_CTYPE:控制字符处理函数在处理大、小写或判断是否是字符。
LC_MESSAGES:提示信息的格式。
LC_MONETARY:货币的格式。
LC_NUMERIC:数字的格式。
LC_TIME:时间的格式。
如果你的locale是en_US.UTF8,那么必须将其修改为zh_CN.UTF8才能正确显示中文。在macOS操作系统的 /usr/share/locale
目录中存放着全部支持的locale:
语言与国家代码
同一种语言在不同国家地区可能有一些细微的差异,比如美国英语和英国英语就有一些差异。同一个国家可能也有多种语言,比如中国有简体与繁体语言。在上述locale的介绍我们看到了使用语言_地域
或语言-地域
的方式来确切的表达一个国家的语言。
对于国家和语言ISO制定了相应的标准代码:ISO 3166-1 与 ISO 639-1。
浏览器使用语言代码来在Accept-Language
HTTP头里发送浏览器接受的语言名。比如:it, de-at, es, pt-br 。
gettext
GNU gettext是GNU国际化与本地化(i18n)函数库,它常被用于编写多语言(multilingualization,缩写为M17N)程序。许多编程语言如C、C++、Python、PHP、Rust、Elixir等都在语言内部支持了gettext的使用。
国际化流程
gettext的使用流程就是一个典型的使应用支持i18n国际化的过程:
- 配置i18n框架。i18n框架通过系统或者浏览器(如果是Web应用)的语言标识自动获取相关的语言文件。如gettext使用的是.mo后缀的文件,而Javascript一般是.json文件,Java是.properties文件。
- 抽取硬编码的源语言文本。在硬编码的地方调用i18n函数。对于这部分可以人工抽取,也可以通过程序或者插件(如Javascript的i18next国际化框架有i18next-scanner)自动抽取。
- 最后实施本地化。翻译(可通过人工或机器翻译,也有相关的翻译平台可以集成)这些抽取出来的要支持的国家语言文件。