点击上方 "程序员小乐"关注, 星标或置顶一起成长
每天凌晨00点00分, 第一时间与你相约
每日英文
You might be worthless to one person, but you're priceless to another.Don’t ever forget your value.
你可能一个人面前一文不值,却在另一个人面前是无价之宝。谨记自己的价值所在。
每日掏心话
幸福更像抽筋,说来就来了,让人迷恋得死去活来,说走却也就走了,那么的干脆,一点都不拖泥带水,甚至连眼泪都来不及落下。
来自:公众号 前端之巅 | 责编:乐乐
程序员小乐(ID:study_tech)第 691 次推文 图片来自网络
正文
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,因为它们没有像函数那样被提升。
你认为它会返回什么值?答案既符合直觉,同时又可以是反直觉的。有人可能会认为第一个 return 语句使函数实际返回并弹出调用栈。但这里是该规则的例外,因为 Finally 语句始终都会运行,因此会返回 Finally 块中的 return 语句。
JavaScript 很容易入门,但很难精通。换句话说,开发人员需要搞清楚自己正在做什么,明白为什么要这样做,否则就很容易出错。
ECMAScript 6 及其含糖功能尤其如此。特别是箭头函数哪里都会冒出来。让我来猜的话,那是因为开发人员认为它们比常规函数更漂亮。但它们不是常规函数,因此无法替代后者。
时不时地浏览一下规范并没有什么坏处。它不是世界上最激动人心的文档,但就规范本身而言写得还算不错。
规范:https://www.ecma-international.org/ecma-262/9.0/index.html
AST Explorer 之类的工具还可以帮助你了解某些极端场景下的状况。人类和计算机往往会以不同的方式来解析事物。
文章最后,我把最后一个示例留作练习供大家思考。
原文链接:
medium.com/better-programming/lesser-known-javascript-hazards-8d688a463b1f
欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。
猜你还想看
![640?](https://img-blog.csdnimg.cn/img_convert/275b5312cf5b9b58c132920345436005.gif)