作为前端开发工程师,JavaScript 是咱们的次要开发语言,它自身语法比较简单,并且生态系统也十分欠缺,在社区的影响力越来越大。

在咱们应用过程中,常常会遇到各种奇怪的问题,让咱们常常摸不着头脑。

本文灵感来自 wtfjs,整顿了 6 个比拟常见并且很有意思的问题。

1. 奇怪的 try..catch

❓问题

上面代码执行后将返回什么?2 还是 3

(() => {  try {    return 2;  } finally {    return 3;  }})();

解答

答案是 3,这是为什么呢?这是因为在 try...catch...finally 语句中,无论是否抛出异样 finally 子句都会执行。此外,如果抛出异样,即便没有 catch 子句解决异样,finally 子句中的语句也会执行。

参考

  • MDN try...catch

2. []null 都是对象

❓问题

上面 3 行代码返回后果是什么?

typeof [];typeof null;null instanceof Object;

解答

返回后果是这样的:

typeof []; // -> 'object'typeof null; // -> 'object'null instanceof Object; // false

typeof 操作符返回一个字符串,且必须合乎 Table 37: typeof 操作符 返回值。对于没有实现 [[Call]]null、一般对象、规范特异对象和非标准特异对象,它返回字符串 'object'

console.log(typeof 42);// expected output: "number"console.log(typeof '前端自习课');// expected output: "string"console.log(typeof true);// expected output: "boolean"console.log(typeof undeclaredVariable);// expected output: "undefined"

然而,你能够应用 toString 办法查看对象的类型。

Object.prototype.toString.call([]);// -> '[object Array]'Object.prototype.toString.call(new Date());// -> '[object Date]'Object.prototype.toString.call(null);// -> '[object Null]'

参考

  • MDN typeof

3. 箭头函数返回 undefined

❓问题

函数 f2 执行后为什么返回了 undefined

let f1 = () => '前端自习课';f1(); // -> '前端自习课'let f2 = () => {};f2(); // -> undefined

解答

咱们第一眼感觉应该是返回 {},可是却返回了 undefined,这实质起因是因为箭头函数返回的 {} 是箭头函数语法的一部分,咱们写一个测试用例就能看进去:

let f2 = () => {    return '前端自习课'};f2(); // -> '前端自习课'

因而下面 f2 函数返回的是 undefined,当然,如果须要返回一个 {} 对象也是能够的,只须要应用括号将返回值包裹起来:

let f2 = () => ({});f2(); // -> undefined

4. 还能应用反引号执行函数?

❓问题

调用函数除了上面的形式,还有其余形式吗?

function f(...args) {  return args;}f(1, 2, 3); // -> [ 1, 2, 3 ]

当然还有啦,咱们能够应用反引号调用:

f`Hello string ${'前端自习课'}, Hello boolean ${false}, Hello array ${[1, 2, 3]}`;/*[    ["Hello string ",  ", Hello boolean ", ", Hello array ", ""],    "前端自习课",    false,    [1, 2, 3]]*/

解答

这个看着很神奇的样子,然而实际上用的是模版字符串。这是一种高级模式的模版字符串,是带标签的模版字符串。

下面示例代码中:f 函数是模版字面量的标签,标签能够用函数解析模板字符串。标签函数的第一个参数蕴含一个字符串值的数组。其余的参数与表达式相干。

参考

  • MDN 模版字符串。

5. JavaScript 中也有标签?

❓问题

上面这种写法会有问题吗?

foo: {  console.log("Hello");  break foo;  console.log("前端自习课");}

解答

答案是没问题,会返回 Hello 的字符串。因为 foo 被辨认为一个标签,而后执行前面 console.log("Hello"),而后执行 break foo 中断执行。

咱们常常会应用带标签的语句和 break/continue 语句一起应用,从而实现完结或持续循环:

let str = '';loop1:for (let i = 0; i < 5; i++) {  if (i === 1) {    continue loop1;  }  str = str + i;}console.log(str);// expected output: "0234"

参考

  • MDN label

6. {}{}undefined

❓问题

咱们能够在控制台测试上面代码。相似这样的构造会返回最初定义的对象中的值。

{}{}; // -> undefined{}{}{}; // -> undefined{}{}{}{}; // -> undefined{foo: 'bar'}{}; // -> 'bar'{}{foo: 'bar'}; // -> 'bar'{}{foo: 'bar'}{}; // -> 'bar'{a: 'b'}{c:' d'}{}; // -> 'd'{a: 'b', c: 'd'}{}; // > SyntaxError: Unexpected token ':'({}{}); // > SyntaxError: Unexpected token '{'

解答

当解析到 {} 会返回 undefined,而解析 {foo: 'bar'}{} 时,表达式 {foo: 'bar'} 返回 'bar'

这里的 {} 有两重含意:示意对象,或示意代码块

例如,在 () => {} 中的 {} 示意代码块。所以咱们必须加上括号:() => ({}) 能力让它正确地返回一个对象。

因而,咱们当初将 {foo: 'bar'} 当作代码块应用,则能够在终端中这样写:

if (true) {  foo: "bar";} // -> 'bar'

啊哈,一样的后果!所以 {foo: 'bar'}{} 中的花括号就是示意代码块

欢送关注我,我将分享更多有用的内容~