鲜为人知的JavaScript陷阱
Posted 前端之巅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鲜为人知的JavaScript陷阱相关的知识,希望对你有一定的参考价值。
const numbers = [1, 2, 3, 4];
numbers.map(function(n) {
return n * n;
});
const numbers = [1, 2, 3, 4];
numbers.map(n => n * n);
在这种用例中,箭头函数的表现符合预期,它将值本身相乘并返回到包含 [1, 4, 9, 16] 的新数组。
const numbers = [1, 2, 3, 4];
numbers.map(n => { value: n });
const numbers = [1, 2, 3, 4];
numbers.map(function(n) {
value:
n
return;
});
const numbers = [1, 2, 3, 4];
numbers.map(n => ({ value: n }));
这会计算出一个包含对象数组的数组,该对象数组具有预期的值。
箭头函数另一个需要注意的点是,它们没有自己的 this 绑定,意味着它们的 this 值和封闭词法作用域的 this 值是一样的。
let calculator = {
value: 0,
add: (values) => {
this.value = values.reduce((a, v) => a + v, this.value);
},
};
calculator.add([1, 2, 3]);
console.log(calculator.value);
尽管人们可能希望这里的 this 绑定为此处的 calculator 对象,但实际上 this 绑定最后要么是未定义,要么是全局对象,具体取决于代码是否在严格模式下运行。这是因为这里最接近的词汇作用域是全局作用域。在严格模式下这是未定义的。否则,它会是浏览器中的窗口对象(或 Node.js 兼容环境中的过程对象)。
let calculator = {
value: 0,
add: (values) => {
this.value = values.reduce((a, v) => a + v, this.value);
},
};
calculator.add([1, 2, 3]);
console.log(calculator.value);
另外,由于箭头函数没有 this 绑定,因此 Function.prototype.call、Function.proto-type.bind 和 Function.prototype.apply 均无法使用。声明箭头函数后,this 绑定设置为固定,无法更改。
const adder = {
add: (values) => {
this.value = values.reduce((a, v) => a + v, this.value);
},
};
let calculator = {
value: 0
};
adder.add.call(calculator, [1, 2, 3]);
箭头函数很简洁,但不能替换需要 this 绑定的常规成员函数。
虽然这不是一项新功能,但自动分号插入(ASI)是 JavaScript 中比较怪异的功能之一,因此值得一提。从理论上讲,你可以在大多数时候省略分号(许多项目都这样做)。如果项目有先例,则应遵循此先例。但你一定需要记得 ASI 是一项功能,否则最后你会写出容易迷惑人的代码。
return
{
value: 42
}
return;
{
value: 42
};
根据经验,即使使用分号时也切勿以大括号、方括号或模板字符串字面量开头,因为 ASI 总是会起作用。
let set = new Set();
set.add([1, 2, 3]);
set.add([1, 2, 3]);
console.log(set.length);
let set = new Set();
set.add([1, 2, 3].join(','));
set.add([1, 2, 3].join(','));
console.log(set.size);
由于字符串是不可变的,且驻留在 JavaScript 中,因此最终的集合大小为 1。如果你需要存储一组对象,那么这就可以是一种解决方法,也可以将它们序列化和反序列化。
let segment = new Segment();
function Segment() {
this.x = 0;
this.y = 0;
}
let segment = new Segment();
class Segment {
constructor() {
this.x = 0;
this.y = 0;
}
}
尝试构造类的新实例时会导致 ReferenceError,因为它们没有像函数那样被提升。
try {
return true;
} finally {
return false;
}
你认为它会返回什么值?答案既符合直觉,同时又可以是反直觉的。有人可能会认为第一个 return 语句使函数实际返回并弹出调用栈。但这里是该规则的例外,因为 Finally 语句始终都会运行,因此会返回 Finally 块中的 return 语句。
JavaScript 很容易入门,但很难精通。换句话说,开发人员需要搞清楚自己正在做什么,明白为什么要这样做,否则就很容易出错。
ECMAScript 6 及其含糖功能尤其如此。特别是箭头函数哪里都会冒出来。让我来猜的话,那是因为开发人员认为它们比常规函数更漂亮。但它们不是常规函数,因此无法替代后者。
时不时地浏览一下规范并没有什么坏处。它不是世界上最激动人心的文档,但就规范本身而言写得还算不错。
规范:https://www.ecma-international.org/ecma-262/9.0/index.html
AST Explorer 之类的工具还可以帮助你了解某些极端场景下的状况。人类和计算机往往会以不同的方式来解析事物。
文章最后,我把最后一个示例留作练习供大家思考。
原文链接:https://medium.com/better-programming/lesser-known-javascript-hazards-8d688a463b1f
偶发 bug 大大增加了排查的成本,复现也变成了所有研发心中的痛。在即将召开的 ArchSummit 全球架构师峰会(北京站)上,贝壳找房基础架构中心前端架构委员会专家陈辰将为大家带来贝壳自研监控平台灯塔之外的另一项目——时光机,揭秘如何利用时光机让偶现 bug 无所遁形。
以上是关于鲜为人知的JavaScript陷阱的主要内容,如果未能解决你的问题,请参考以下文章