语法和数据类型

JavaScript语法

大小写敏感

JavaScript区分大小写,并使用Unicode字符集。即变量testTEXT是两个不同的变量,并且可以使用中文作为变量名,如:var 中文;

分号可省略

每行代码结尾的分号可以省略,因为ECMAScript规定了在语句的末尾自动插入分号(ASI机制)。如果一行中有多条语句,那么这些语句必须以分号隔开。

语法

JavaScript源码从左往右被扫描并转换成一系列由token、控制字符、行终止符、注释和空白字符组成的输入元素。

  • 控制字符
    • 零宽非连字符(<ZWNJ>, U+200C),放置在一些经常会被当成连字的字符之间,用于将它们分别以独立形式显示。
    • 零宽连字符(<ZWJ>, U+200D),放置在一些通常不会被标记为连接字的字符之间,用于将这些字符以连字形式显示。
    • 字节顺序标记(<BOM>, U+FEFF),在脚本开头使用,除了将脚本标记为Unicode格式以外,还用来标记文本的字节流方向。
  • 空白符
    • 制表符(<HT>, U+0009),水平制表符,\t
    • 垂直制表符(<VT>, U+000B),垂直制表符,\v
    • 分页符(<FF>, U+000C),分页符,\f
    • 空格(<SP>, U+0020),空格
    • 无间断空格(<NBSP>, U+00A0),在该空格处不会换行
  • 行终止符
    • 换行符(<LF>, U+000A),在UNIX系统中起新行,\n
    • 回车符(<CR>, U+000D),在Commodore和早期的Mac系统中起新行,\r
    • 行分隔符(<LS>, U+2028)
    • 段分隔符(<PSs>, U+2029)

注释

JavaScript的注释语法类似于C++,有两种注释方式:单行和多行。两种注释方式不能混用。

1
2
3
4
// 单行注释
/*
多行注释
*/

变量

变量又叫标识符,需要遵循一定的规则:必须以字母、下划线(_)或者美元符($)开头,后续的字符也可以是数字(0-9),可以使用ISO 8859-1或Unicode编码的字符作为标识符。

1
2
var \u4e25 = 1;     // 严的unicode编码为\u4e25
console.log(严); // 1
  • 变量声明

    • 使用关键词var,例如var test = 1;。该语法可以声明局部变量和全局变量。
    • 直接赋值,例如test = 1;。在函数外使用这种形式赋值会产生一个全局变量,在严格模式下会产生错误。
    • 使用关键词let,例如let test = 1;。该语法可以用来声明块作用域的局部变量
  • 变量求值

    varlet声明的变量如果没有赋初始值,则其值为undefined。如果访问一个未声明的变量会抛出一个·ReferenceError异常。

    可以使用undefined来判断一个变量是否已经赋值,例如:

    1
    2
    3
    4
    5
    6
    var test;
    if(test === undefined) {
    console.log('test变量未赋值');
    }else{
    console.log('test变量已赋值');
    }

    由于undefined在布尔类型环境中会被当做false,所以上面的代码可以简化成下面的形式:

    1
    2
    3
    4
    5
    6
    var test;
    if(test) {
    console.log('test变量未赋值');
    }else{
    console.log('test变量已赋值');
    }

    在数值类型中undefined会被转成NaN,例如:

    1
    2
    var a;
    console.log(a+2); // NaN

    空值null在数值类型中会被转换成0,在布尔类型中会准换成false,例如:

    1
    2
    3
    4
    5
    var a = null;
    console.log(a + 1); // 1
    if(!a){
    console.log('null');
    }
  • 变量的作用域

    在函数之外生声明的变量叫做全局变量,它可被当前文档中的任何其他代码访问。在函数内部声明的变量称为局部变量,只能在当前函数内部访问。

    1
    2
    3
    4
    var test;    // 全局变量
    function Test() {
    var test; // 局部变量
    }

    在ECMAScript6之前没有块级作用域(即大括号之间的代码块),语句块中声明的变量会称为语句块所在的作用域中的变量。如果使用ES6中的let声明,就会变为块级作用域。

    1
    2
    3
    4
    {
    let test = 1;
    }
    console.log(test); // ReferenceError
  • 变量提升

    在JavaScript中可以先使用变量再进行声明,这被称为变量提升。感觉上提升是被移到了文档的最前面,但提升后的变量将返回undefined值,因此即便是在声明时赋值了初始值,也会返回undefined

    1
    2
    3
    console.log(a);    // undefined
    var a = 10;
    console.log(a); // 10

    在ECMAScript6中,使用letconst声明会将变量提升但不会被初始化,因此在变量声明之前就使用这个变量,将会抛出引用错误(RefenceError)。这个变量将从代码块一开始的时候就处在一个暂时性死区(temporal dead zone),直到这个变量被声明为止。

    1
    2
    console.log(a);    // ReferenceError
    let a = 10;
  • 函数提升

    对于函数来说,只有函数声明会被提升,而函数表达式不会被提升。

    1
    2
    3
    4
    5
    6
    7
    8
    test();    // test!
    function test() {
    console.log('test!')
    }
    test2(); // TypeError: test2 is not a function
    var test2 = function() {
    console.log('test2!')
    }
  • 全局变量

    全局变量实际上是全局对象的属性,在浏览器中默认的全局变量为window,可以使用window.variable的语法来设置和访问变量。

  • 常量

    在ECMAScript6中,可以使用const关键字声明常量,常量不可以重新赋值,所以在声明时就需要赋值。常量作用域与let一样,在同一作用域中,不能使用变量名或函数名相同的名字来命名常量。

    1
    2
    const a = 10;
    function a() {} // SyntaxError: Identifier 'b' has already been declared

数据类型

最新的ECMAScript定义了8中数据类型,分别为:

  • 原始类型
    • Boolean,有且只有两个值: truefalse
    • Null,一个表明null值得特殊关键字,
    • undefined,一个表示值未定义的顶级属性
    • Number,整数或浮点数
    • String,代表文本值的一系列字符
    • Symbol,实例是唯一且不可变的数据类型
    • BigInt,具有任意精度的整数
  • Object

类型转换

JavaScript是一门动态类型的语言,在声明变量时可以不必指定数据类型,数据类型会在代码执行时根据需要自动转换。

1
2
var a = 10;    // 此时a的类型为number
a = '1234'; // 此时a的类型为string

在包含数字和字符串的表达式中使用+运算,JavaScript会将数字隐式转换成字符串。

1
console.log('37' + 1);    // 371,类型为字符串,使用字符串的拼接操作

在涉及其他运算符时,JavaScript会将字符串隐式转换成数字

1
console.log('37' - 1);    // 36,类型为数字

字面量

字面量是在脚本中实际提供的固定值而不是变量,通常有以下类型的字面量:

  • 数组字面量(Array Literals)

    数组字面量是0个或多个表达式的列表,每个表达式代表一个数组元素,并使用方括号[]括起来。使用数组字面量创建数组时,将使用指定的值作为其元素进行初始化,并且将其长度设置为指定的参数个数。

    1
    2
    3
    4
    let nums = [1, ,3];
    nums[0]; // 1
    nums[1]; // undefined
    nums[2]; // 3
  • 布尔字面量(Boolean Literals)

    有且仅有两个值:truefalse

  • 浮点数字面量(Float-point Literals)

    浮点数字面量可以有以下部分组成:

    • 一个带正负号(+-)的十进制整数
    • 小数点.
    • 小数部分(由一串十进制数表示)
    • 指数部分,即eE后跟一个整数,该整数可以带正负号。

    浮点数字面量必须至少包含一位数字,并带有小数点或e。语法类似:

    1
    [(+|-)][digits].[digits][(E|e)[(+|-)]digits]
  • 数字字面量(Numeric Literals)

    Number和BigInt类型可以使用十进制、十六进制、八进制和二进制表示。

    • 十进制的数字字面量是由前缀不为0的一串数字序列组成
    • 八进制的数字字面量是由前缀为0或者前缀为0O的只包含0-7的数字组成
    • 十六进制的数字字面量是由前缀为0x并且包含0-9和a-f的序列组成
    • 二进制的数字字面量是由前缀为0b并且只包含0-1的数字序列组成
  • 对象字面量(Object Literals)

    对象字面量是使用花括号{}括起来的0或多对属性名:属性值对的元素列表。不要在语句的开头使用对象字面量语法,这位被认为是一个块的开始

    增强的对象字面量(Enhanced Object literals)

    在ES2015中,对象字面量扩展了支持在创建时设置原型,简写了foo: foo形式的属性赋值和方法定义,支持父方法调用,以及使用表达式动态计算属性名。

    1
    2
    3
    4
    5
    6
    var obj = {
    __proto__: theProtoObj,
    handler, // => handler: handler
    toString() {}, // => toString: function() {}
    ['prop_' + (() => 42)()]: 42 // 动态计算属性名
    }
  • 正则表达式字面量(RegExp Literals)

    正则表达式字面量是被斜杠/围成的表达式,例如:

    1
    var re = /ab+c/;
  • 字符串字面量(String Literals)

    字符串字面量是由双引号"或单引号'括起来的0个或多个字符,字符被限制在相同类型的引号之间。例:

    1
    2
    var a = 'test';
    var b = "test";

    ES2015还提供了一种模板字面量(template literals),模板字面量使用反引号(`),其为构造字符串提供了语法糖,还可以在模板字符串前添加一个tag来自定义模板字符串的解析过程,以预防注入攻击或建立基于字符串的高级数据抽象。例:

    1
    2
    var name = 'bob';
    console.log(`Hello, ${name}`); // Hello, bob

本文参考资料

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • © 2019-2021 musi

请我喝杯咖啡吧~

支付宝
微信