5

前言

前段时间调试代码,查看对象的toString的返回数据,由于比较简单,直接在浏览器的控制台输出代码

{}.toString();    // Uncaught SyntaxError: Unexpected token .

“.”不是期待的表达式,{}在JS中不是一个再正常不过的对象么,于是试了一下其他对象类型数据。

[].toString();    // ""
function(){}.toString();    // Uncaught SyntaxError: Unexpected token (
/^\.$/.toString();    // "/^\.$/"

查资料看了一下,总的来说涉及到JS这门语言设计的几个概念:语句、函数声明、语句块等

语句

JS中,应用程序是由许多语法正确的语句组成的,语句的作用就是告诉浏览器应该怎样执行程序。语句之间使用“;”作为结尾,其中主要包括表达式语句、块语句、空语句和声明语句,这里不细讲。

注意上面一段话中的语法正确一词,在前言的demo代码中,数组和正则表达式可以正常调用的,但是对象和方法类型调用却是失败的,网上大部分答案回答都比较浅显:”JS中语句不能以function或者大括号作为开始,会报错“。对于这句话,只能说对错一半吧!

先来说一下为什么语句不能以”function“开始,这里涉及到函数声明的概念。

函数声明

函数声明:定义一个具有指定参数的函数,以function开头, 其中包括函数名,参数名,和函数语句块

举个栗子?:

function funcName(arg1, arg2) {
    // 语句块
}

我们代码中调用toString方法”function(){}.toString“,是以”function“开头的, JS中会将以”function“ 开头的语句认定为函数声明语句,那么代码必须符合函数声明语句规范,很明显”function“后未包括函数名,这条函数声明语句明显不符合规范。

正确的做法:

// 以”(“开头的语句JS并不会将其视作函数声明
(function(){}).toString();
// 匿名函数
(function(){})()
// 匿名函数装B一点的写法
void function(){}()

非函数申明代码不可以“function”作为语句开头,那大括号又是怎么回事呢。

语句块

将零个或多个语句联合在一起,形成一条复合语句,用大括号将其包括

有的文档上叫“块语句”,也有人的文档上叫复合语句,举个栗子?,我们可以这样写代码:

{
    console.info('输出一个语句');
    console.info('不出错,是不是很神奇');
};

也就是说如果我们以大括号开头,浏览器会理解将其视作一个语句块,语句块中的代码和外面的代码并没有本质的区别,也是从上至下而执行。再看个栗子?:

{};    // undefined
{a: 'a'};    // 'a';
{a: 'a'}.a;    // Uncaught SyntaxError: Unexpected token .

第一行很好理解,没有任何执行语句,当然输出undefined
第二行代码呢,输出“a”,这里不要被“:”给蒙蔽了,这里的的冒号是一个标识符,类似于C语言中的标记符,不同的是JS中通过“break”与“continue”跳转到标记符,二C语言中是通过“goto”,关于标记符
第三行代码等同于:“a: 'a'; .a;” 没有通过对象主体获取属性“a”,所以报错。

综上所述,“{}.toString();” 等同于: “; .toString();” 未通过对象主体调用“toString”方法,不符合JS中期待的表达式

说了这么多,用语句块有什么好处呢,我能想到的唯一好处只有“装B耍酷”...

总结在最后

JS语句为什么不能以“function”和大括号开头呢?

  • 以function开头,但必须是一个函数声明语句
  • 以大括号开头,但该大括号不再被当做一个对象处理,而是当做一个语句块处理
  • 综上两条说明,JS语句可以以function,也可以以大括号作为开头,前提是必须符合JS中的语法规范

参考资料

MDN 语句
MDN 语句块
MDN 标记符
MDN Unexpected token
expressions-vs-statements
MDN Expressions_and_Operators


petruslaw
651 声望11 粉丝

你还没有成为真正的孙悟空,是因为你还没有遇见那个给你脚底三颗痣的人~