一些好吃的JavaScript小技巧
实际上是开发微信小程序我踩过的一些坑,也是我的学习笔记,如果你想实现类似的功能,或者遇到类似问题,可以参考这篇文章。
-
针对多维数组,在原有数据的后面追加数据
知识点:
...扩展运算符,用于数组的展开。**情景:**包含时间、传感器值的二维数据的数组,形如
[[11:45:14, 1.23], [11:45:15, 2.33]]。需要在后面插入相同形式的数据。**方法:**使用扩展运算符
...展开原数组和追加数组,然后合并为新数组。例子:
1
2
3const oldData = res.data || [];
const newData = [...oldData, ...removed];
wx.setStorageSync(currentDate, newData);Q&A:
-
**Q:**为什么不能直接写
[oldData, removed]?**A:**因为数组没展开,返回的是2个二维数组,是错误的结果。
-
-
从一个多维数组中提取指定内容,并构成新序列
知识点:
- **
map方法:**将原数组映射为指定的形式,创建一个新数组,需要一个变量来承载新数组。 - **
=>箭头函数:**函数的简写,结构为参数 => 返回值,类似于C的lambda。会继承外部的this,保持其指向不变。
**情景:**包含时间、传感器值的二维数据的数组,形如
[[11:45:14, 1.23], [11:45:14, 2.33]]。需要从数组中提取时间轴和数值轴的数据序列,构成新数组,作为折线图的x轴和y轴数据源。**方法:**使用箭头函数提取指定的元素,用
map方法将其映射为新的数组。例子:
1
2
3const time = this.data.dataList.map(item => item[0]);
const value = this.data.dataList.map(item => item[1]);
// 对每个dataList处理一次,将其中的所有第0或第1个元素返回,映射到一个新数组,作为time或者value保存下来 - **
-
处理错误的
SetTimeout()函数知识点:
SetTimeout()函数,延时结束后自动执行。延时单位是毫秒。**情景:**用户按下按钮,启动设备。你需要给用户返回不同的状态,你用
SetTimeout()函数来判断超时,超时自动返回【连接失败】。你很聪明,想到了要用标志位来解决,也就是设置一个标志位,例如
deviceState.start.success来表征设备启用状态,当你监听到设备启用,执行回调,把这个值设置为true,SetTimeout()延时结束后判断这个值的真假,阻止设备启动后,显示错误状态。但如果用户~~在酒馆里点了一份炒饭~~在设备成功启动后迅速点击关闭,然后再启用设备,假设上述过程在你设置的超时期限以内,那就会错误触发超时,返回【连接失败】。
**方法:**在执行启动设备的指令成功后,清除定时器(前提是你能监听到执行成功)
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13//延时函数,先用一个变量保存延时函数
this.data.isDeviceLaunched = setTimeout(() => {
if (!this.data.deviceState.start.success) {
this.setDeviceState('start', 'fail');
}
}, 5000);
//设备启用成功的回调
() => {
this.data.deviceState.start.success = true;
this.setDeviceState('start', 'succcess');
clearTimeout(this.data.isDeviceLaunched);
},
-
Echarts图表:启用
tooltip/axisPointer时的undefined错误知识点:
Echarts图表(如需使用,请先阅读官方文档)/ axisPointer / tooltip**情景:**你引用
Apache Echarts图表,使用折线图来显示一些传感器的值随时间的变化。但是你发现,点击某个数据点的时候,你并不知道它具体的值是多少。你认为这对用户来讲不太友好。所以你引入了tooltip/axisPointer,希望能够帮用户读清楚数据。实际测试的时候,你发现了问题:假设10月20日的数据有5个点,10月21日的数据有2个点。当你点击10月20日的第3个数据,然后通过下拉菜单切换到10月21日。此时
tooltip/axisPointer就有概率返回undefined值。原因:
tooltip/axisPointer不会随着图表数据源的切换而刷新,原本10月21日的第3个点本来就没有值。**方法:**让需要的组件在切换数据源之后刷新一次就好了。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//由constant.js引入,只需重置tooltip,xAxis,yAxis,series四项即可避免undefined错误
export let newEchartsOption = {
tooltip: echartsOption.tooltip,
xAxis: echartsOption.xAxis,
yAxis: echartsOption.yAxis,
series: echartsOption.series
}
//用于重绘图表的函数
redrawEchart() {
var option = newEchartsOption
this.chart.clear();
this.chart.setOption(option, {
replaceMerge: ['xAxis', 'yAxis', 'series', 'tooltip']
});
}
-
关于
this通常,在 JS 中,this 的真正决定因素是 函数被调用的方式。this 的指向并不确定。
而在微信小程序里,由于微信小程序框架会在你调用
Page()或Component()时自动创建一个对象实例。这个实例就是页面或组件的“运行时对象”。通常,一个页面自动创建的 JS ,结构是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18Page({
data: {
data1: 0,
data2: {name1: 'test'}
},
onLoad(options) {
},
onReady() {
},
onShow() {
},
}在这里引用
this,微信框架会使它指向这个Page下的实例。换句话说,需要引用Page下的东西,都可以用this。例如引用
data1,就是this.data.data1。引用name1的test这个字串,就是this.data.data2.name1。如果你在
Page下自定义了一些函数,饮用方法也是如此。例如下面的代码,在
onLoad里调用myFunction():1
2
3
4
5
6
7
8
9
10
11
12
13
14Page({
data: {
data1: 0,
data2: {name1: 'test'}
},
onLoad(options) {
this.myFunction();
},
myFunction() {
console.log("myFunction");
}
}但是由于
this的特性,也可能出现一些问题。例如在下面的代码中:
1
2
3
4
5
6
7
8wx.getStorageInfo({
success: function (res) {
console.log("成功读取缓存信息");
this.setData({
data1: res,
});
},
})就会出现下面的报错:
1
this.setData is not a function
这是由于
this的作用域导致的。因为success是个闭包,无法直接获取外部的this结构,既然这些东西也就不存在。解决办法也很简单,就是使用箭头函数,或者先传入
this,再用that集成。箭头函数会继承外层的this,不改变其指向。如下:
1
2
3
4
5
6
7
8wx.getStorageInfo({
success: (res) => {
console.log("成功读取缓存信息");
this.setData({
data1: res,
});
},
})
