1.初始化数组(初始化一个指定长度的一维数组,并指定默认值)
const array=Array(5).fill('')
// ['','','','','']
2.初始化一个指定长度的二维数组,并指定默认值
const matrix = Array(6).fill(0).map(() => Array(5).fill(0));
3.数组求和、求最大值、最小值
const array = [5,4,7,8,9,2];
// 求和
array.reduce((a,b) => a+b);
// 最大值
array.reduce((a,b) => a > b ? a : b);
Math.max(...array)
// 最小值
array.reduce((a,b) => a < b ? a : b);
Math.min(...array)
4.过滤错误值(滤数组中的false、0、null、undefined等值)
const array = [1, 0, undefined, 6, 7, '', false]
array.filter(Boolean)
5.使用逻辑运算符
if(a > 10) { doSomething(a) }
a > 10 && doSomething(a)
6.判断简化
if(a === undefined || a === 10 || a=== 15 || a === null) {
if([undefined, 10, 15, null].includes(a)) {
7.清空数组
let array = ["A", "B", "C", "D", "E", "F"]
array.length = 0 console.log(array)
7. 计算代码性能
// 可以使用以下操作来计算代码的性能:
const startTime = performance.now()
// 某些程序
for(let i = 0
const endTime = performance.now()
const totaltime = endTime - startTime
console.log(totaltime)
8. 拼接数组
const start = [1, 2]
const end = [5, 6, 7]
const numbers = [9, ...start, ...end, 8]
start.concat(end);
Array.prototype.push.apply(start, end)
9. 对象验证方式
const parent = {
child: {
child1: {
child2: {
key: 10
}
}
}
}
parent && parent.child && parent.child.child1 && parent.child.child1.child2
parent?.child?.child1?.child2
const array = [1, 2, 3]; array?.[1]
10. 验证undefined和null
if(a === null || a === undefined) {
doSomething()
}
a ?? doSomething()
11. 数组元素转化为数字
const array = ['12', '1', '3.1415', '-10.01'];
array.map(Number);
12. 类数组转为数组
Array.prototype.slice.call(arguments);
[...arguments]
13. 对象动态声明属性
const dynamic = 'color';
var item = {
brand: 'Ford',
[dynamic]: 'Blue'
}
console.log(item);
14. 缩短console.log()
const c = console.log.bind(document)
c(996)
c("hello world")
15. 获取查询参数
// 如果我们想要获取URL中的参数,可以使用window对象的属性:
window.location.search
// 如果一个URL为www.bai.com?project=js&type=1 那么通过上面操作就会获取到?project=js&type=1。如果在想获取到其中某一个参数,可以这样:
// let type = new URLSearchParams(location.search).get('type')
16. 数字取整
~~3.1415926
- 如果是数字类型的字符串,就会转化为纯数字;
- 如果字符串包含数字之外的值,就会转化为0;
- 如果是布尔类型,true会返回1,false会返回0;
23.9 | 0
-23.9 | 0
17. 删除数组元素
const array = ["a", "b", "c", "d"]
array.splice(0, 2)
18. 检查对象是否为空
Object.keys({}).length
Object.keys({key: 1}).length
19. 使用 switch case 替换 if/else
switch case 相对于 if/else 执行性能更高,代码看起来会更加清晰。
if (1 == month) {days = 31
else if (2 == month) {days = IsLeapYear(year) ? 29 : 28
else if (3 == month) {days = 31
else if (4 == month) {days = 30
else if (5 == month) {days = 31
else if (6 == month) {days = 30
else if (7 == month) {days = 31
else if (8 == month) {days = 31
else if (9 == month) {days = 30
else if (10 == month) {days = 31
else if (11 == month) {days = 30
else if (12 == month) {days = 31
// 使用switch...case来改写:
switch(month) {
case 1: days = 31
case 2: days = IsLeapYear(year) ? 29 : 28
case 3: days = 31
case 4: days = 30
case 5: days = 31
case 6: days = 30
case 7: days = 31
case 8: days = 31
case 9: days = 30
case 10: days = 31
case 11: days = 30
case 12: days = 31
default: break
}
// 更优的方法: 策略模式
// 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。它提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展。
let commodity = {
phone: '手机',
computer: '电脑',
television: '电视'
gameBoy: '游戏机',
}
function price(name) {
if (name === commodity.phone) {
console.log(1999)
} else if (name === commodity.computer) {
console.log(9999)
} else if (name === commodity.television) {
console.log(2999)
} else if (name === commodity.gameBoy) {
console.log(3999)
}
}
price('手机') // 9999
const commodity = new Map([
['phone', 1999],
['computer', 9999],
['television', 2999],
['gameBoy', 3999],
])
const price = (name) => {
return commodity.get(name)
}
price('phone') // 1999
20. 获取数组中的最后一项
arr.slice(-1)
// 当我们将slice方法的参数设置为负值时,就会从数组后面开始截取数组值,如果我们想截取后两个值,参数传入-2即可。
21. 值转为布尔值
- undefined
- null
- 0
- -0
- NaN
- ""
!!undefined
!!"996"
!!null
!!NaN
24. 函数参数使用对象而不是参数列表
function getItem(price, quantity, name, description) {}
getItem(15, undefined, 'bananas', 'fruit')
function getItem(args) {
const {price, quantity, name, description} = args
}
getItem({
name: 'bananas',
price: 10,
quantity: 1,
description: 'fruit'
})
25. includes 的优化
function verifyIdentity(identityId) {
if (identityId == 1 || identityId == 2 || identityId == 3 || identityId == 4) {
return '你的身份合法,请通行!'
} else {
return '你的身份不合法'
}
}
function verifyIdentity(identityId) {
if ([1, 2, 3, 4].includes(identityId)) {
return '你的身份合法,请通行!'
} else {
return '你的身份不合法'
}
}
for 循环
// 在 JavaScript 中,我们可以使用 `for()`, `while()`, `for(in)`,`for(of)`几种循环,事实上,这三种循环中 `for(in)` 的效率极差,因为他需要查询散列键,所以应该尽量少用。
//for 循环是最传统的语句,它以变量 i 作为索引,以跟踪访问的位置,对数组进行操作。
var arr = ['a', 'b', 'c']
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]) //结果依次a,b,c
}
// 以上的方法有一个问题:就是当数组的长度到达百万级时,`arr.length` 就要计算一百万次,这是相当耗性能的。所以可以采用以下方法就行改良。
var arr = ['a', 'b', 'c']
for (var i = 0, length = arr.length; i < length; i++) {
console.log(arr[i]) //结果依次a,b,c
}
// 此时 `arr.length` 只需要计算一次,优化了性能。
// `for-in` 一般用来来遍历对象的属性的,不过属性需要 `enumerable`(可枚举)才能被读取到。同时 `for-in` 也可以遍历数组,遍历数组的时候遍历的是数组的下标值。
var obj = { 0: 'a', 1: 'b', 2: 'c' }
for (var key in obj) {
console.log(key) //结果为依次为0,1,2
}
var arr = ['a', 'b', 'c']
for (var key in a) {
console.log(key) //结果为依次为0,1,2
}
// `for-of` 语句看着有点像 `for-in` 语句,但是和 `for-of` 语句不同的是它不可以循环对象,只能循环数组。
var arr = ['a', 'b', 'c']
for (var value of arr) {
console.log(value) // 结果依次为a,b,c
}
// `for-of` 比 `for-in` 循环遍历数组更好。`for-of` 只要具有 `Iterator` 接口的数据结构,都可以使用它迭代成员。它直接读取的是键值。`for-in` 需要穷举对象的所有属性,包括自定义的添加的属性也能遍历到。且 `for-in` 的 `key` 是 `String` 类型,有转换过程,开销比较大。
// 所以在开发过程中循环数组尽量避免使用 `for-in`。
Dom 的创建
// 创建多个 dom 元素时,先将元素 `append` 到 `DocumentFragment` 中,最后统一将 `DocumentFragment` 添加到页面。
// 常规方法;
for (var i = 0
var el = document.createElement('p')
el.innerHTML = i
document.body.appendChild(el)
}
// 使用 `DocumentFragment` 优化多次 `append`
var frag = document.createDocumentFragment()
for (var i = 0
var el = document.createElement('p')
el.innerHTML = i
frag.appendChild(el)
}
document.body.appendChild(frag)
// 更优的方法:使用一次 `innerHTML` 赋值代替构建 dom 元素
var html = []
for (var i = 0
html.push('<p>' + i + '</p>')
}
document.body.innerHTML = html.join('')
内存泄漏
1、未声明变量或者使用 `this` 创建的变量(`this` 的指向是 `window`)都会引起内存泄漏
function fn() {
a = "Actually, I'm a global variable"
}
fn()
function fn() {
this.a = "Actually, I'm a global variable"
}
fn()
- 避免创建全局变量
- 使用严格模式,在 JavaScript 文件头部或者函数的顶部加上 `use strict`。
2、在 vue 单页面应用,声明的全局变量在切换页面的时候没有清空
<div id="home">
</div>
export default {
mounted() {
window.test = {
name: 'home',
node: document.getElementById('home')
}
}
}
destroyed () {
window.test = null
}
闭包引起的内存泄漏原因:闭包可以维持函数内局部变量,使其得不到释放。
function fn() {
var a = "I'm a"
return function () {
console.log(a)
}
}
由于项目中有些页面难免会碰到需要定时器或者事件监听。但是在离开当前页面的时候,定时器如果不及时合理地清除,会造成业务逻辑混乱甚至应用卡死的情况,这个时就需要清除定时器事件监听,即在页面卸载(关闭)的生命周期函数里,清除定时器。
methods:{
resizeFun () {
this.tableHeight = window.innerHeight - document.getElementById('table').offsetTop - 128
},
setTimer() {
this.timer = setInterval(() => { })
},
clearTimer() {
clearInterval(this.timer)
this.timer = null
}
},
mounted() {
this.setTimer()
window.addEventListener('resize', this.resizeFun)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeFun)
this.clearTimer()
}
防抖与节流
// 在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 `resize`、`scroll`、`mousemove` 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。这时候就用到防抖与节流。
// 案例 1:远程搜索时需要通过接口动态的获取数据,若是每次用户输入都接口请求,是浪费带宽和性能的。
<Select :remote-method="remoteMethod">
<Option v-for="item in temoteList" :value="item.value" :key="item.id">{{item.label}}</Option>
</Select>
<script>
function debounce(fn, wait) {
let timeout = null
return function () {
if (timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn, wait)
}
}
export default {
methods:{
remoteMethod:debounce(function (query) {
}, 200),
}
}
<script>
function debounce(fn, wait) {
let timeout = null
return function () {
if (timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn, wait)
}
}
function handle() {
console.log(Math.random())
}
window.addEventListener('scroll', debounce(handle, 1000))