JavaScript基础语法详解:标识符、关键字与变量作用域
本文系统梳理JavaScript基础语法,涵盖标识符命名规范、关键字与保留字列表、ES5严格模式开启方式及注释规范。重点解析变量声明机制,深入剖析var操作符、动态类型特性以及全局与局部作用域的区别,并通过代码实例详细解释变量与函数声明提升原理,帮助开发者规避常见作用域陷阱。
JavaScript基础语法概述
本篇内容旨在复习ECMAScript规范中的基础语法部分。具备英语阅读能力的开发者可直接参考官方文档。JavaScript在语法结构上类似于C语言,熟悉C语言的读者阅读起来会非常顺畅,甚至可以直接跳过,但仍建议通读全文,因为文中可能会引用一些虽然不常见但颇具代表性的用法。
基础语法
标识符与关键字规范
1、标识符:标识符是指符合特定规范、能被JavaScript引擎识别的名称,用于表示常量、变量、函数名、函数参数、对象及其属性等所有可命名实体。
(1)区分大小写。
(2)标识符必须以字母、下划线(_)或美元符号($)开头,后续字符可以是字母、下划线、美元符号或数字。这里的“字母”包括扩展的ASCII字符或Unicode字符。
(3)标识符不能是语言的关键字、保留字,也不能是true、false或null。(注:部分浏览器允许使用undefined作为标识符,而部分浏览器则不允许)。
(4)如果对象属性名包含空格或其他特殊字符,可以使用方括号将其括起来作为一个整体访问。
2、关键字:这些词汇在语言本身中具有特定的语法用途。
break case catch continue debugger(ES5中新增) default delete do else finally for function if in instanceof new return switch this throw try typeof var void while with
3、保留字:这些词汇被语言保留,未来可能成为关键字。
ES3中的保留字:
abstract boolean byte char class const debugger double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile
ES5中的非严格模式下的保留字:
class const enum export extends import super
ES5的严格模式下的保留字:
implements interface let(ES5中新增) package private protected public static yield(ES5中新增)
严格模式与注释规范
4、严格模式:ES5引入了严格模式,通过字符串"use strict"来启用。可以在脚本顶部开启全局严格模式,也可以在函数内部开启局部严格模式。
代码如下:
"use strict"//开启全局严格模式,在ES3环境中,这行代码不会产生任何影响function fn(){
"use strict"//开启局部严格模式
} 5、注释:ECMAScript支持两种注释格式:单行注释和块级注释。
代码如下:
// 单行注释,以两个斜杠//开头/*
* 多行(块级)注释,以一个斜杠/和一个星号*开头,以星号*和斜杠/结尾。中间行的星号*并非必须。
*/ 说明:随着JavaScript代码复杂度的增加,注释的重要性日益凸显,文档自动化工具也变得愈发关键。目前已有许多开源JavaScript库用于自动生成类似Javadoc风格的JS文档,例如JSDoc、YUIDoc等。这些工具对注释格式有特定要求,有兴趣的开发者可以查阅相关资料进行深入研究。
变量声明与作用域机制
6、变量:从本质上看,变量只是内存空间在编程语言层面的抽象表示。
(1)动态类型:在ECMAScript中,变量是动态类型的。你可以在定义时将其初始化为Number类型,随后立即将字符串值赋给它:
代码如下:
var age = 29;
age = 'twenty-nine'; //尽管JavaScript允许这种灵活性,但我建议除非你非常清楚自己在做什么,否则不要这样做。 (2)var操作符:变量使用var关键字声明。对于未初始化的变量,其默认值为undefined。也可以直接使用变量而不进行声明(在我看来,这是一个缺乏存在理由的特性)。两者最重要的区别在于:使用var声明的变量仅在当前作用域内有效,而不使用var直接赋值的变量则会成为全局变量。可以通过以下示例体会其中的差异:
代码如下:
var name = 'linjisong'; //定义并赋值全局变量
age = 29; //直接赋值变量,相当于定义并赋值全局变量
//sal; //错误:未声明的变量
var salary; //定义全局变量,但未初始化
//此处仅为函数声明,并未实际调用,因此函数内部定义的变量不会生效
function fn(){
var name = 'oulinhai';//定义并赋值局部变量
age = 23; //给全局变量age赋值
work = 'it'; //未使用var,即使在函数局部定义的变量,也会成为全局变量
}
//在函数实际调用之前
console.info(salary); //输出:undefined
console.info(name); //输出:linjisong
console.info(age); //输出:29
try{
console.info(work);//由于全局环境中未定义work,此处会抛出异常
}catch(e){}
fn();//实际调用函数,代码中对变量的变更将显现出来
console.info(name); //输出:linjisong,由于函数内部使用了var,因此不会更改全局的name值
console.info(age); //输出:23
console.info(work); //输出:it 声明提升原理详解
(3)声明提升:此问题在讲解函数声明和函数表达式时会再次涉及,此处先做简要介绍,请看代码:
代码如下:
console.info(name);//输出:undefined
console.info(getName);//输出:getName()函数
console.info(getName());//输出:undefined
try{
console.info(age);//抛出异常
}catch(e){
console.info(e);//ReferenceError
}
console.info(getAge);//输出:undefined
try{
console.info(getAge());//抛出异常
}catch(e){
console.info(e);//TypeError
}
var name = 'linjisong';//变量声明,发生提升
age = 29;//直接使用全局变量,不发生提升
function getName(){//函数声明,发生提升
return name;
}
var getAge = function(){//变量getAge的声明发生提升;获取年龄的匿名函数表达式不发生提升
return age;
}
console.info(name);//输出:linjisong
console.info(getName);//输出:getName()函数
console.info(getName());//输出:linjisong
console.info(age);//输出:29
console.info(getAge);//输出:获取年龄的匿名函数
console.info(getAge());//输出:29 你是否能推断出上述代码的输出结果?如果已经清楚,可以跳过;如果仍有疑问,请先阅读下方关于声明提升的说明,然后再回头验证上述输出结果:
A、引擎在解析代码时,首先会处理函数声明,然后处理变量声明(解析时不会覆盖类型),最后才执行代码;
B、解析函数声明时,会同时解析类型(即函数),但不会执行函数体;解析变量声明时,仅解析变量名,不进行初始化。
上述讨论仅涉及全局作用域,在函数作用域中,函数参数也与声明提升有关,这将在后续讲解函数时进一步讨论。
对于上述代码,引擎首先会将第18行的函数声明以及第16、21行的变量声明提升到代码最前端进行解析,然后再执行后续代码。因此,第1、9行由于变量声明提升但尚未初始化,输出undefined,导致第11行因无法确定类型而抛出类型异常;第2、3行由于函数声明提升并解析了函数类型,所以第2行输出函数定义,第3行可以调用函数,但返回值未初始化而输出undefined;第5行由于变量尚未声明,会抛出引用异常。
(4)可以使用一条语句定义多个变量,只需使用逗号分隔即可。例如:
代码如下:
var name='linjisong',
age=29,
work='it'; (5)在ES5的严格模式下,不允许定义名为eval或arguments的变量。
语句与代码块特性
7、语句
(1)语句:以分号“;”结尾。如果省略分号,由解析器确定语句的结尾。
对于JavaScript中语句可以省略分号的特性,我找不到任何合理的存在理由。强烈建议每条语句均使用分号明确结束,不要浪费解析器的时间去“猜测”你的程序意图。更重要的是,在许多代码压缩工具中,这种猜测并不能保证100%的正确性。
(2)代码块:以左花括号({)开始,右花括号(})结束。
虽然JavaScript中有代码块的概念,但并不具备相应的块级作用域,这与一般的类C语言不同。对于控制语句(如if),即使只有一条语句,也不应省略代码块,这会给后续维护代码的人埋下犯错的隐患。
代码如下:
for(var i=0; i<10; i++)
{
}
console.info(i);//输出10,在代码块之后仍可访问i,说明JavaScript没有块级作用域
if(i < 10)
//console.info(i); 不使用代码块,在维护时(例如添加1条语句)容易犯错
{
console.info(i);
} 花括号({})除了用作代码块外,还有一个重要用途是定义对象字面量,这将在后续章节中详细论述。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
