不加分号可能会使代码错误执行

故事背景

今天在刷leetcode46. 全排列的时候,出现了一个令人费解的问题

js 复制代码
var permute = function (nums) {
  const res = []
  const backtrack = (first = 0) => {
    if (first === nums.length) {
      res.push([...nums])
      return
    }
    for (let i = first; i < nums.length; i++) {
      [nums[first], nums[i]] = [nums[i], nums[first]]
      backtrack(first + 1);
      [nums[first], nums[i]] = [nums[i], nums[first]]
      //                     ^
      // TypeError: Cannot set properties of undefined (setting '3')
    }
  }
  backtrack()
  return res
};

脑子过了一遍好像,for中没有能取到3的时候,于是打log看看在什么情况下i的取值会到3,于是便有下面不同的报错

js 复制代码
var permute = function (nums) {
  const res = []
  const backtrack = (first = 0) => {
    if (first === nums.length) {
      res.push([...nums])
      return
    }
    console.log('---')
    for (let i = first; i < nums.length; i++) {
      console.log(first, i)
      [nums[first], nums[i]] = [nums[i], nums[first]]
      //                     ^
      // TypeError: Cannot set properties of undefined (setting '1')
      backtrack(first + 1)
      [nums[first], nums[i]] = [nums[i], nums[first]]
    }
  }
  backtrack()
  return res
};

先说解决方法:给backtrack()加上引号问题

分析原因:

假设有const arr = ['a', 'b', 'c'],有2个前置知识点要先了解

  1. 当你在数组后面的方括号[中使用逗号分隔的多个索引时,它实际上会返回最后一个索引对应的元素。 arr[1,2] => arr[2] => 'c'
  2. 解构赋值的语法将数组中的值交换位置时,整个表达式返回交换之后的结果 [arr[1], arr[2]] = [arr[2], arr[1]] => ['c', 'b']

因此第一个错误中,有如下执行过程

scss 复制代码
backtrack(first + 1)
[nums[first], nums[i]] = [nums[i], nums[first]]

// 等价于下面的代码
backtrack(first + 1)[nums[first], nums[i]] = [nums[i], nums[first]]

// 当first = 2,执行代码变成这样
backtrack(3)[3,3] 
=> backtrack(3)[3] 
=> undefined[3]

因此便有了,TypeError: Cannot set properties of undefined (setting '3')

结论

JavaScript引擎会使用一个叫做自动分号插入(Automatic Semicolon Insertion,ASI)的机制,在代码解析时在某些地方自动插入分号。 JavaScript引擎试图在这两行代码之间插入一个分号,但是由于数组解构赋值的语法,它误解了这两行代码,导致了TypeError。

参考资料:

  • JavaScript 不会将每个换行符都视为分号:通常仅当无法解析没有分号的代码时,它才会将换行符视为分号。 因此以 "("、"["、"/"、"+"、"-" 开始的语句,那么它极有可能和前一条语句合在一起解释。 《JavaScript:权威指南》第 6 版(David Flanagan,O'Reilly,2011)中收集到的内容:

  • 尤雨溪在JavaScript语句后应该加分号么?中的回答: 至于说 "很难总结什么时候加不加",其实真的很简单。 真正会导致上下行解析出问题的 token 有 5 个:括号,方括号,正则开头的斜杠,加号,减号。 我还从没见过实际代码中用正则、加号、减号作为行首的情况, 所以总结下来就是一句话:一行开头是括号或者方括号的时候加上分号就可以了,其他时候全部不需要。其实即使是这两种情况,在实际代码中也颇为少见。

相关推荐
JUNAI_Strive_ving11 分钟前
番茄小说逆向爬取
javascript·python
看到请催我学习20 分钟前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
twins352040 分钟前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky1 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
哪 吒1 小时前
华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)
javascript·python·华为od
安冬的码畜日常1 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
Q_w77422 小时前
一个真实可用的登录界面!
javascript·mysql·php·html5·网站登录
昨天;明天。今天。2 小时前
案例-任务清单
前端·javascript·css
一丝晨光2 小时前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby