「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」
一、JSON.parse对象转换问题
obj = JSON.parse(data)时候报错:
SyntaxError: Unexpected token . in JSON at position 0
原因:
- data已经是对象了。
- JSON.parse():将JSON字符串转换成JSON对象
- JSON.stringify():将JSON对象转换成JSON字符串
二、ajax发HTTP请求时报错:
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.
中文翻译:
在主线程同步XMLHttpRequest是不赞成的,因为对最终用户的体验有不利影响。
原因:
以上警告信息在ajax方法执行同步操作(等有了返回值才执行下面的js,会短暂阻断程序继续执行)的时候出现,即:async:false。
如果业务层面允许,推荐异步执行AJAX,即将async属性设置为true。(async缺省下为true)
如果非要使用同步的Ajax(这种情况应该很少见),HTML5中增加了Worker对象,每个Worker运行在一个独立的线程中,Worker线程被阻塞一般是不会影响主线程和浏览器的。
三、console.log打印的问题
其实有时候打印的不是当前值,点开可以看到有个感叹号提示value below was evaluated just now
四、const和let的区别
let声明的变量可以改变,值和类型都可以改变,没有限制。
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
五、forEach究竟能不能改变数组的值
因为forEach效率高选用forEach,结果发现无法修改数组的值,详见
总结:
若原数组oldArr的元素是基本数据类型,则如下:
oldArr.forEach((el)=>{
el = 2
})
是没法将数组oldArr中的每个值改成2的。
若一定要将原数组oldArr中的数值改为2,则可通过明确数组下标的方式修改,如下即可:
oldArr.forEach((el,index)=>{
oldArr[index] =2
})
六、定时器的问题
原来有个定时器,这么写:
function MapInit (flag) {
pageFlag = flag
svgDoc = null
if (svgDoc === null) {
clearTimeout(timeSvgDoc)
console.log(111)
timeSvgDoc = setTimeout(MapInit(1), 1000)
} else {
……
}
}
结果:控制台飞速打印111,直达栈溢出
思考:
- 1、怀疑有多个定时器存在,于是加上clearTimeout(timeSvgDoc),没用。
- 2、考虑修改时间间隔,1000改为10000即10s钟,发现没用任何影响,飞速打印111。
- 3、对比其他正常的定时器,发现写法不对,改为如下即可。
function MapInit (flag) {
pageFlag = flag
svgDoc = null
if (svgDoc === null) {
clearTimeout(timeSvgDoc)
timeSvgDoc = setTimeout(() => {
MapInit(1)
}, 1000)
} else {
……
}
}
原因:
问题在于定时器setTimeout的第一个参数要求是一个函数,比如
setTimeout(MapInit,1000)
但是因为函数带了参数时,第一个参数其实是函数的返回值了,如下:
setTimeout(MapInit(1),1000)
所以马上执行了MapInit函数获取其返回值,而返回值定时1s后执行并没有什么效果。
七、JS浮点数运算的误差问题
经典问题:
0.1 + 0.2 === 0.3 // false
同样的系统中碰到:
30-19.47=10.530000000000001
问题原因:
因为浮点数运算的时候,先转化为二进制,用二进制来算,结果再转回十进制。
而浮点数19.47转化为二进制是个无限循环小数,只能取近似值,误差就这么产生了。
解决办法:
用toFixed()四舍五入为指定的小数位数即可。
八、typeof和instanceof的一个问题
判断对象类型时经常出现如下问题
typeof aaa // "string"
aaa instanceof String // false
为什么?怎么办?
首先了解一下typeof和instanceof分别是什么:
typeof
此操作符返回一个字符串,表示未经计算的操作数的类型。
下表总结了typeof常见的返回值
等,详见developer.mozilla.org/zh-CN/docs/…
额外的,我们可以巧用typeof来判断一个变量是否存在,用typeof a !== "undefined"代替if(a)更好,因为如果a为定义if(a)会报错。
instanceof
该运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置,oops有点听不太懂。
详见
developer.mozilla.org/zh-CN/docs/…
里面有提到String对象的一些特殊情况
var simpleStr = "This is a simple string";
simpleStr instanceof String; // 返回 false, 检查原型链会找到 undefined
这不就回答了我常遇见的问题!!
然后,分析如下:
simpleStr和aaa一样,只是一个以string为数据类型的值,并不是String的实例对象。
aaa instanceof String 在只有左侧是右侧类的对象时才会返回ture
aaa instanceof Object 的结果同样是false(所有对象都是Object的实例)
也就是说aaa本身并不是任何一个类的实例,如图
若将这个数据类型转换为String的类对象就会出现如下情况:
var bbb = new String(aaa);
bbb instanceof String //ture
最后可改为如下判断:
typeof aaa // "string"
aaa instanceof String // false
typeof aaa === 'string' // true
九、replaceAll('_', '.')时不时报错replaceAll is not a function
某些浏览器某些版本可以使用replaceAll('_', '.')进行全部替换,某些又报错replaceAll is not a function。
总之少用replaceAll,用.replace(/_/g, '.')即可。
十、foreach是无法跳出循环的
看到有人说 return false 可以,但也只是相当于for循环中的continue,而不是break。
其实,我觉得这个命名就很准确了,我就是来foreach的,for每一个啊,你不要for每一个那你就去用for循环啊。
十一、双层for循环的问题
for (let i = 0; i < aaa.length; i++) {
for (let j = 0; j < bbb.length; j++) {
if ((bbb[j].id === aaa[i].epId) && (aaa[i].epId === 1)) {
// 注意有两层循环
// 如果if条件想当然的改写为if (bbb[j].id === 1) 是不对的,会进来多次。
}
}
}
十二、es6对象定义简写
let aaa = 'a'
原来写法:
let param1 = { aaa: aaa} // { aaa: 'a' }
简写:
let param2 = { aaa } // { aaa: 'a' }
十三、window.localStorage和localStorage
查阅资料后,两者的区别个人理解如下:
localStorage是全局对象window中的一个,调用时可以省略window。
比如alert()方法,window.alert()和alert()也是一样的。
十四、关于空格
 
 
都是空格,但是空格不可累加,无论写多少个,就只有一个空格。
十五、iframe通信(里层>外层)
iframe里层发送信息:
window.top.postMessage(err.data, '*')
- 第一个参数:向iframe外层传递的信息
- 第二个参数:要发送到的地址(这里有个问题,我就是拿不到外层的URL地址啊,所以只能配置*,群发。)
iframe外层监听信息:
let that = this
window.addEventListener('message', function (event) { // 监听postMessage传过来的信息
console.log(event)
}, false)
十六、定时器和异步请求连用时销毁有问题
有如下代码:
timeaaa是一个定时器对象,收到异步接口的返回后,清除上一个定时器,开启下一个定时器。
页面销毁时,清除定时器。
这里有个现象,当多次触发接口调用时,离开页面销毁时,定时器未成功清除。
一开始我始终不解,这里只有一个timeaaa对象,始终将定时器赋值给它,最后清除,为什么还会存在定时器?
同事解惑:
定时器返回的是一个数值,如果同时生成了多个定时器对象,clearTimeout时,只清除了第二个1816,第一个还是存在的。
所以如果要解决这个问题,需要从外部解决掉这个定时器的漏洞。
可以考虑用请求取消来解决。
十七、数组的指向引用问题
若定义一个对象等于某个数组,此时修改对象属性,原数组也会跟着变动。
let arr = [0,1,2]
let aaa = arr
aaa[0] = 123
console.log(aaa) // [123,1,2]
console.log(arr) // [123,1,2]
因为数组的存储方式导致的正常现象。
所以在诸如选中一行表格内容进行编辑修改时,需要注意特殊处理,让列表的数据不会跟着变化。
十八、数组排序
对象数组arr中根据某个属性值进行升序/降序排序:
ascendSort (arr, key) {
// 升序排序
return arr.sort((a, b) => a[key] - b[key])
// 降序排序 arr.sort((a, b) => b[key] - a[key])
},