JavaScript已经存在了很长时间(大约26年),在这段时间里,这种语言有了很大的发展。
这种演变大多是有目的的,尤其是在最新的迭代中。开发人员社区已经成功地影响了其中的一些变化,使得JavaScript成为一种非常灵活且易于使用的语言。
但是在这几年的演变过程中,可以说还是有一些残留的过时功能,还没有去掉,但是真的没有用了(或者说,在原来的使用中效率低下)。
以下三个JavaScript特性,即使在运行时仍然可用,也应该避免。
Void运算符
你可能在某个时候见过void算子的存在。过去,每当你点击一个会触发JavaScript函数的链接时,你都会添加href = & # 8221JavaScript:void(0)”以确保不会触发默认行为(即页面跳转)。
但是这到底是什么意思呢?
void运算符是一种在JavaScript中生成未定义值的方法。没错,它可以接受任何表达式,每次都返回undefined。
我知道你在想什么:为什么不直接使用现有的未定义的关键字?正如你所看到的,在ECMAScript 5之前,undefined关键字不是一个常量值。是的,你可以定义未定义。你再想想,我们以前不也是这么想的吗?
当然这样做是没有意义的,这也是为什么最后它被重新定义为一个常量值,无法更改的原因。但是,因为您可以提前更改它,所以void将允许您访问undefined,即使该常量不再有效。
其实一个很好的办法就是通过创建自己的IIFEs来重新定义只属于你命名空的常量,避免任何第三方库的问题。其中一个参数确实没有定义,就像这样:
(function (window, undefined) { // 你这里的逻辑,可以把 undefined 当作预期})(window, void(0))
当然今天的void运算符还是有它的用处的,只是没必要了。例如,在今天的JavaScript中,最好的用例是帮助避免单行箭头函数的意外返回。
您可能知道,单行箭头函数将返回该行的结果,即使您没有显式使用return语句。
const double = x => x * 2; // 返回 X 乘以 2 的结果const callAfunction = () => myFunction(); // 返回 myFunction 所返回的结果,即使我不想这样做
两个函数都会返回一些东西。显然,对于double function,你希望它返回值,而另一个可能不返回值。你可能只是想用它调用另一个函数(即myFunction()),而对它的结果值不感兴趣。所以你可以这样做:
const callAfunction = () => void myFunction(); // 返回 myFunction 所返回的结果,即使我不想这样做
这将立即覆盖返回值,并确保您的调用值返回undefined。
对我来说,这种行为提供了一个最小的好处,使得void在这个时代的JavaScript中毫无用处。
建议大家避免使用,保持废弃状态。
With语句
它是JavaScript的内置结构之一,但你可能从来没有听说过,因为它并没有得到真正的推广。事实上,即使是MDN官方文档也不鼓励您使用它,因为它可能会导致非常混乱的代码。
With语句允许您扩展给定语句的作用域链。换句话说,它允许你在给定语句的范围内注入一个表达式,理想情况下,它可以简化语句。
这里有一个例子,这样你就会明白我想说什么:
function greet(user) { with(user) { console.log(`Hello there ${name}, how are you and your ${kids.length} kids today?`) }}greet({ name: "Fernando", kids: ["Brian", "Andrew"]})
注意greet函数中with语句的魔力。这是一个基本的例子,展示了幸福的表达方式。但是,让我们看看另一种情况,事情变得有点复杂:
function greet(user, message) { with(user) { console.log(`Hey ${name}, here is a message for you: ${message}`) }}// happy pathgreet({ name: "Fernando"}, "You got 2 e***ils")// kinda sad pathgreet({ name: "Fernando", message: "Unrelated message"}, "you got e***il")
你认为这种执行方式的输出结果会是什么?
Hey Fernando, here is a message for you: You got 2 e***ilsHey Fernando, here is a message for you: Unrelated message
因为您向传递的对象添加了一个同名的属性,所以无意中覆盖了函数的第二个参数。我想补充一点,这是完全正常的,因为人们绝不会期望两者在同一个作用域级别。但是,由于有了with,我们混合了两种作用域,但结果并不理想。
都是关于避免使用with。虽然看起来可能是节省代码量的好方法,但是你的代码很快就会变得非常复杂,给别人(或者两周后的你)理解你的代码造成精神负担。
标签标签
如果你学编程学得够早(像我一样),你就体会过其他语言(比如C)对go-to语句的厌恶。那太糟糕了。在那个年代是一个很有意义的函数,但是最后随着同一个问题的更新解决方案,这个函数变得如此过时和糟糕,以至于成为了一个反模式。
所以JavaScript必须实现它。
Go-to语句是一种在代码中的任何地方放置标记,然后从其他地方跳转到那里的方法。你可以跳到一个函数的中间,或者一个IF语句中。它就像一个神奇的入口,可以跳到你代码中的任何地方。我相信你能看出这可能是个问题。它太强大太灵活了,我们肯定会错过使用它的机会。
然而,JavaScript实现了一个相似但不完全相同的结构:标签。
JavaScript中的标记语句是一个放在语句前面的标记,然后可以中断或继续。请注意,没有更多的go-to,这是一个很好的优势。
你可以这样写:
label1: { console.log(1) let condition = true if(condition) { break label1 } console.log(2)}console.log("end")
输出结果将是:
1end
当然,这个例子看起来很像一个假设..else语句。你完全可以说它看起来没那么糟糕。但是,您破坏了代码的正常流程,跳过了语句。如果那是你想要的,那么使用If的精神负担..别的会少很多。
当我们用循环和continue语句包含标签的交互时,标签的问题变得更加明显。
let i, j;loop1:for(i = 0; i < 10; i++) { loop2: for(j = 0; j < 10; j++) { if(j == 3 && i == 2) { continue loop2; } console.log({i, j}) if(j % 2 == 0) { continue loop1; } }}
能不能在脑子里运行一下上面的代码,告诉我具体的输出结果?不是不可能,只是需要一些时间。上面的脚本将打印出来:
{ i: 0, j: 0 }{ i: 1, j: 0 }{ i: 2, j: 0 }{ i: 3, j: 0 }{ i: 4, j: 0 }{ i: 5, j: 0 }{ i: 6, j: 0 }{ i: 7, j: 0 }{ i: 8, j: 0 }{ i: 9, j: 0 }
本质上,第二个if的值为0,所以continue语句影响外部循环,使其移动到下一个索引值,这又会重置内部循环,使其返回到0。同样的事情不断发生,重复10次。如果你想知道的话,第一个if永远不会计算为true,因为j永远不会达到0以外的任何值。
标签可能是棘手的小问题,即使你可以正确地使用它们,从解释者的角度来看,它们很有意义,但你应该为人类而不是机器编写代码。别人会看(甚至三周后的你),看到标签,会恨你一辈子。当然,他们会花更多的时间去理解你代码的基本流程,但这在目前是次要问题。
本文摘要
请不要误会,我喜欢JavaScript这种语言。自从18年前开始从事web开发工作以来,我一直以不同的方式与它互动。我见证了这种语言的发展,就像一瓶好酒,随着时间的推移越来越好。但是,如果我说这种语言里没有我不喜欢的黑暗角落,那是假的。而这三个功能恰恰说明了这一点。
好消息是,在我多年的经验中,我还没有见过在生产中实现和部署with或Label。这并不是说没有这种情况,只是我之前没见过,让我感觉没有多少代码评审会让他们通过。
你见过现代JavaScript中使用的这些函数吗?
本文来自Rose情調※投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/570751.html