第3章 基本概念

211 阅读22分钟

3.1语法

ECMAScript 的语法大量借鉴了 C 及其他类 C 语言(如 Java 和 Perl)的语法。

3.1.1 区分大小写

ECMAScript 中的一切(变量、函数名和操作符)都区分大小写。

3.1.2 标识符

  • 第一个字符必须是一个字母、下划线(_)或一个美元符号($);
  • 其他字符可以是字母、下划线、美元符号或数字。

ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每个单词的首字母大写,例如: doBest,goSleep,learnMore

3.1.3 注释

// 单行注释

块级注释

/*
* 这是一个多行
* (块级)注释
*/

3.1.4 严格模式

ECMAScript 5 引入了严格模式(strict mode)的概念。

全局作用域开启严格模式,在首行代码书写:

"use strict";

指定函数在严格模式下执行,在该函数块首行:

function doSomething(){
    "use strict";
    //函数体
}

3.1.5 语句

ECMAScript 中的语句以一个分号结尾;如果省略分号,则由解析器确定语句的结尾。

条件控制语句(如 if 语句)只在执行多条语句的情况下才要求使用代码块但最佳实践是始终在控制语句中使用代码块——即使代码块中只有一条语句,例如:

if (test) alert(test); // 有效但容易出错,不要使用

if (test){ // 推荐使用
    alert(test);
}

3.2 关键字和保留字

关键字

break do instanceof typeof
case else new var
catch finally return void
continue for switch while
debugger
function this with
default if throw
delete in try

保留字

abstract enum int short
boolean export interface static
byte extends long super
char final native synchronized
class float package throws
const goto private transient
debugger implements protected volatile
double import public

3.3 变量

ECMAScript 的变量是松散类型的,可以用来保存任何类型的数据。换句话说,每个变量仅仅是一个用于保存值的占位符而已。 不要定义名为 eval 或 arguments 的变量,严格模式会报错。

var 操作符

定义了一个名为 message 的变量,保存一个特殊的值——undefined。

var message;

变量 message 中保存了一个字符串值"hi"。

var message = "hi";

var 操作符定义的变量将成为定义该变量的作用域中的局部变量。当函数被调用时,就会创建该变量并为其赋值。 而在此之后,这个变量又会立即被销毁。

function test(){
    var message = "hi"; // 局部变量
}
test();
alert(message); // 错误!

省略了var 操作符,message 就成了全局变量。(不推荐)

function test(){
    message = "hi"; // 全局变量
}
test();
alert(message); // "hi"

可以使用一条语句定义多个变量

var message = "hi",
found = false,
age = 29;

3.4 数据类型

ECMAScript 中有 5 种简单数据类型:Undefined、Null、Boolean、Number和 String

还有 1种复杂数据类型——Object

3.4.1 typeof操作符

typeof 操作符可以判断基本类型,除了null,但是可以判断function类型

"undefined"——如果这个值未定义,或者未声明;
"boolean"——如果这个值是布尔值;
"string"——如果这个值是字符串;
"number"——如果这个值是数值;
"object"——如果这个值是对象或 null"function"——如果这个值是函数。

3.4.2 Undefined类型

Undefined 类型只有一个值,即特殊的 undefined。

3.4.3 Null类型

Null 类型是第二个只有一个值的数据类型,这个特殊的值是 null。

如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为 null 而不是其他值。

3.4.4 Boolean类型

Boolean 类型只有两个字面值:true 和 false。 要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolean()。

数据类型转换为true的值转换为false的值
Booleantruefalse
String任何非空字符串""(空字符串)
Number任何非零数字值(包括无穷大)0和NaN
Object任何对象null
Undefinedn/a(或 N/A),是 not applicable 的缩写,意思是“不适用”。undefined

流程控制语句(如 if 语句)自动执行相应的 Boolean 转换。

var message = "Hello world!";
if (message){
    alert("Value is true");
}

3.4.5 Number类型

不同进制的数据

var intNum = 55; // 整数
// 八进制字面值的第一位必须是零(0),然后是八进制数字序列(0~7)。
// 八进制字面量在严格模式下是无效的,会导致支持的 JavaScript 引擎抛出错误。
var octalNum1 = 070; // 八进制的 56
var octalNum2 = 079; // 无效的八进制数值——解析为 79
var octalNum3 = 08; // 无效的八进制数值——解析为 8
// 十六进制字面值的前两位必须是 0x,后跟任何十六进制数字(0~9 及 A~F)。
var hexNum1 = 0xA; // 十六进制的 10
var hexNum2 = 0x1f; // 十六进制的 31

浮点数值

所谓浮点数值,就是该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。
浮点数值需要的内存空间是保存整数值的两倍
var floatNum1 = 1.; // 小数点后面没有数字——解析为 1
var floatNum2 = 10.0; // 整数——解析为 10

数值范围

Number.MIN_VALUE:表示的最小数值。
Number.MAX_VALUE:表示的最大数值。
当计算结果大于Number.MAX_VALUE时,这个数值将被自动转换成特殊的 Infinity 值
当计算结果小于Number.MIN_VALUE时,这个数值将被自动转换成特殊的 -Infinity

isFinite()函数,用于判断一个数值是不是有穷。

var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result)); //false

NaN

   即非数值(Not a Number)是一个特殊的数值。
   
   ECMAScript中,任何数值除以 0会返回 NaN。 
   任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaNNaN 与任何值都不相等,包括 NaN 本身。
   

isNaN()

isNaN()在接收到一个值之后,会尝试将这个值转换为数值。不能换为数值,则为true,能转换为数值,则为false。

alert(isNaN(NaN)); //true
alert(isNaN(10)); //false(10 是一个数值)
alert(isNaN("10")); //false(可以被转换成数值 10)
alert(isNaN("blue")); //true(不能转换成数值)
alert(isNaN(true)); //false(可以被转换成数值 1)

Number()

可以用于任何数据类型。Number()函数的转换规则如下:

如果是 Boolean 值,truefalse 将分别被转换为 10。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。
如果是字符串,遵循下列规则:
    如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1"
    会变成 1"123"会变成 123,而"011"会变成 11(注意:前导的零被忽略了,因此无法转成8进制数);
    
    如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,也会忽
    略前导零);
    
    如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值;
    
    如果字符串是空的(不包含任何字符),则将其转换为 0;
    
    如果字符串中包含除上述格式之外的字符,则将其转换为 NaN

parseInt()函数,专门用于把字符串转换成整数

它会忽略字符串前面的空格(不是忽略0,这里跟Number()不一样),直至找到第一个非空格字符。

如果第一个字符不是数字字符,parseInt()就会返回 NaN;

用 parseInt()转换空字符串会返回 NaN

如果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了
一个非数字字符

如果字符串中的第一个字符是数字字符,parseInt()也能够识别出各种整数格式(除了八进制)

所以最好指定第二个参数,转换时使用的基数(即多少进制)。

parseFloat()

专门用于把字符串转换为浮点数,只解析十进制数

parseFloat()也是从第一个字符(位置 0)开始解析每个字符。
而且也是一直解析到字符串末尾,或者解析到遇见第二个小数点的浮点数字字符为止。
十六进制格式的字符串则始终会被转换成 0

3.4.6 String类型

String 类型用于表示由零或多个 16 位 Unicode 字符组成的字符序列,即字符串。字符串可以由双引号(")或单引号(')表示,因此下面两种字符串的写法都是有效的:

var firstName = "Nicholas";
var lastName = 'Zakas';

不过,以双引号开头的字符串也必须以双引号结尾,而以单引号开头的字符串必须以单引号结尾。

字符字面量

\n      换行
\t      制表
\b      空格
\r      回车
\f      进纸
\\      斜杠
\'      单引号('),在用单引号表示的字符串中使用。例如:'He said, \'hey.\''
\"      双引号("),在用双引号表示的字符串中使用。例如:"He said, \"hey.\""
\xnn    以十六进制代码nn表示的一个字符(其中n为0~F)。例如,\x41表示"A"
\unnnn  以十六进制代码nnnn表示的一个Unicode字符(其中n为0~F)。例如,\u03a3表示希腊字符Σ

字符串的特点

ECMAScript 中的字符串是不可变的,要改变某个变量的字符串,其实是一个销毁旧的和创建新的字符串的过程。

转换为字符串

toString()

数值、布尔值、对象和字符串值都有toString()方法。但null和undefined值没有这个方法。 对于数值类型,toString()方法默认以十进制格式返回数值的字符串表示,也可以通过传递基数输出不同的有效进制格式的字符串,如:

var num = 10;
alert(num.toString()); // "10"
alert(num.toString(2)); // "1010"
alert(num.toString(8)); // "12"
alert(num.toString(10)); // "10"
alert(num.toString(16)); // "a"

String()

String()函数遵循下列转换规则:

如果该值有 toString()方法,则调用该方法(没有参数)并返回相应的结果;
如果该值是 null,则返回"null";
如果该值是 null,则返回"null"

使用加号操作符(+) 与空串("")拼接

3.4.7 Object类型

ECMAScript 中的对象其实就是一组数据和功能的集合。对象可以通过new操作符创建:

var o = new Object();
var o = new Object; // 有效,但不推荐省略圆括号

Object 的每个实例都具有下列属性和方法。

  1. constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor)就是 Object()。
  2. hasOwnProperty():  方法返回一个布尔值,表示对象自有属性(而不是继承来的属性)中是否具有指定的属性。
  3. isPrototypeOf(object):方法返回一个布尔值,用于测试一个当前调用对象是否存在于入参对象的原型链上。
  4. propertyIsEnumerable(propertyName):方法返回一个布尔值,表示指定的属性是否可枚举。
  5. toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
  6. toString():返回对象的字符串表示。
  7. valueOf():返回对象的字符串、数值或布尔值表示。

3.5 操作符

3.5.1 一元操作符

递增和递减操作符

递增和递减操作符直接借鉴自 C,而且各有两个版本:前置型和后置型。

递增和递减不仅适用于整数,还可以用于字符串、布尔值、浮点数值和对象。不同的值遵循下列规则:

  • 字符串、布尔值时先调用Number()方法转为有效数值,再进行加减操作。不能转为有效数值的,结果为NaN。
  • 在应用于浮点数值时,执行加减 1 的操作。
  • 在应用于对象时,先调用对象的 valueOf()方法以取得一个可供操作的值。然后对该值应述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规则。对象变量变成数值变量。

“+”操作符

  • 放在数值前面,对数值不会产生任何影响
  • 非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换

“-”操作符

  • 一元减操作符主要用于表示负数
  • 作用于数值前表示对该值取反
  • 而当应用于非数值时,一元减操作符遵循与一元加操作符相同的规则,最后再将得到的数值转换为负数
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
    valueOf: function() {
        return -1;
    }
};
s1 = -s1; // 值变成了数值-1
s2 = -s2; // 值变成了数值-1.1
s3 = -s3; // 值变成了 NaN
b = -b; // 值变成了数值 0
f = -f; // 变成了-1.1
o = -o; // 值变成了数值 1

3.5.2 位操作符

ECMAScript 中的所有数值都以 IEEE-754 64 位格式存储,但位操作符并不直接操作 64 位的值。而是先将 64 位的值转换成 32 位的整数,然后执行操作,最后再将结果转换回 64 位。(这就是为什么0.1+0.2 != 0.3的原因)

3.5.3 布尔操作符

逻辑非

逻辑非操作符由一个叹号(!)表示,可以应用于 ECMAScript 中的任何值。无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再:对其求反。也就是说,逻辑非操作符遵循下列规则:

  • 如果操作数是一个对象,返回 false;
  • 如果操作数是一个空字符串,返回 true;非空字符串,返回 false;
  • 如果操作数是数值 0,返回 true;任意非 0 数值(包括 Infinity),返回 false;
  • 如果操作数是 null 或者 undefined,返回 true;
  • 如果操作数是 NaN,返回 true;

同时使用两个逻辑非操作符,实际上就会模拟 Boolean()转型函数的行为。

逻辑与

逻辑与操作符由两个和号(&&)表示,有两个操作数。逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。

逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。

  • 如果第一个操作数是 falsy值,则不会执行第二个操作数。
  • 如果第一个操作数是 truthy值, 则返回第二操作数的结果。

逻辑或

逻辑或操作符由两个竖线符号(||)表示,有两个操作数。

与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为true,就不会对第二个操作数求值了。

  • 如果第一个操作数是 truthy值,则不会执行第二个操作数。
  • 如果第一个操作数是 falsy值, 则返回第二操作数的结果。

3.5.4 乘性操作符

ECMAScript 定义了 3 个乘性操作符:乘法、除法和求模。

乘法

乘法操作符由一个星号(*)表示,用于计算两个数值的乘积。有以下规则:

  • 如果操作数都是数值,执行常规的乘法计算
  • 如果有一个操作数是 NaN,则结果是 NaN;
  • 如果是 Infinity 与 0 相乘,则结果是 NaN;
  • 如果是 Infinity 与非 0 数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
  • 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
  • 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

除法

除法操作符由一个斜线符号(/)表示,有以下规则:

  • 如果操作数都是数值,执行常规的除法计算
  • 如果有一个操作数是 NaN,则结果是 NaN;
  • 如果是 Infinity 被 Infinity 除,则结果是 NaN;
  • 如果是零被零除,则结果是 NaN;
  • 如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
  • 如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
  • 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

求模

求模(余数)操作符由一个百分号(%)表示,用法如下:

  • 如果操作数都是普通数值,执行常规的除法计算,返回除得的余数;
  • 如果被除数是Infinity而除数是普通数值,则结果是 NaN;
  • 如果被除数是普通数值而除数是零,则结果是 NaN;
  • 如果是 Infinity 被 Infinity 除,则结果是 NaN;
  • 如果被除数是普通的数值而除数是Infinity,则结果是被除数;
  • 如果被除数是零,则结果是零;
  • 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
3 % 2 // 1
Infinity  % 2 // NaN
Infinity  % Infinity  // NaN
2 % Infinity   // 2
0 % 2 // 0
'12' % 5 // 相当于 Nummber('12') % 5, 结果 为 2

3.5.5 加性操作符

加法

加法操作符(+)的用法如下所示: 如果两个操作符都是数值,执行常规的加法计算,然后根据下列规则返回结果:

  • 如果有一个操作数是 NaN,则结果是 NaN;
  • 如果是 Infinity 加 Infinity,则结果是 Infinity;
  • 如果是-Infinity 加-Infinity,则结果是-Infinity;
  • 如果是 Infinity 加-Infinity,则结果是 NaN;

不过,如果有一个操作数是字符串,那么就要应用如下规则:

  • 如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
  • 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来。
  • 如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值,然后再应用前面关于字符串的规则。
  • 对于 undefined 和 null,则分别调用 String()函数并取得字符串"undefined"和"null"。

减法

减法操作符(-)是另一个极为常用的操作符,其用法如下所示:

  • 如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
  • 如果有一个操作数是 NaN,则结果是 NaN;
  • 如果是 Infinity 减 Infinity,则结果是 NaN;
  • 如果是-Infinity 减-Infinity,则结果是 NaN;
  • 如果是 Infinity 减-Infinity,则结果是 Infinity;
  • 如果是-Infinity 减 Infinity,则结果是-Infinity;
  • 如果有一个操作数是字符串、布尔值、null 或 undefined,则先在后台调用 Number()函数将其转换为数值,然再根据前面的规则执行减法计算。如果转换的结果是 NaN,则减法的结果就是 NaN;
  • 如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值。如果得到的值是 NaN,则减法的结果就是 NaN。如果对象没有 valueOf()方法,则调用其 toString()方法并将得到的字符串转换为数值。

只有一种表达式结果为-0

-0-0 // 结果为-0

3.5.6 关系操作符

小于(<)、大于(>)、小于等于(<=)和大于等于(>=)这几个关系操作符用于对两个值进行比较,比较的规则与我们在数学课上所学的一样。这几个操作符都返回一个布尔值

当关系操作符的操作数使用了非数值时,也要进行数据转换或完成某些奇怪的操作。

如果两个操作数都是数值,则执行数值比较。

  • 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
  • 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
  • 如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面的规则执行比较。
  • 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。

3.5.7 相等操作符

相等和不相等——先转换再比较,全等和不全等——仅比较而不转换。

在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:

  • 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而true 转换为 1;
  • 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
  • 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较;
  • null 和 undefined 是相等的。
  • 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
  • NaN 不相等于任何值,包括他自己
  • 如果两个操作数都是对象,则比较它们是不是同一个对象。

3.5.8 条件操作符

variable = boolean_expression ? true_value : false_value;

3.5.9 赋值操作符

简单的赋值操作符由等于号(=)表示,其作用就是把右侧的值赋给左侧的变量

3.5.10 逗号操作符

使用逗号操作符可以在一条语句中执行多个操作,如下面的例子所示:

var num1=1, num2=2, num3=3;

逗号操作符还可以用于赋值。在用于赋值时,逗号操作符总会返回表达式中的最后一项

var num = (5, 1, 4, 8, 0); // num 的值为 0

3.6 语句

3.6.1 if语句

大多数编程语言中最为常用的一个语句就是 if 语句。以下是 if 语句的语法:

if (condition) statement1 else statement2

其中的 condition(条件)可以是任意表达式;当这个表达式求值的结果不是布尔值时,ECMAScript 会自动调用 Boolean()。如果对 condition求值的结果是 true,则执行 statement1(语句 1)。如果对 condition求值的结果是 false,则执行 statement2(语句 2)

3.6.2 do-while语句

do-while 语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次。

var i = 0;
do {
    i += 2;
} while (i < 10);
alert(i);

3.6.3 while语句

while 语句属于前测试循环语句,也就是说,在循环体内的代码被执行之前,就会对出口条件求值。因此,循环体内的代码有可能永远不会被执行。

var i = 0;
while (i < 10) {
    i += 2;
}

3.6.4 for语句

for 语句也是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代码的能力。

var count = 10;
for (var i = 0; i < count; i++){
    alert(i);
}

使用while循环实现

var count = 10;
var i = 0;
while (i < count){
    alert(i);
    i++;
}

使用 while 循环做不到的,使用 for 循环同样也做不到。也就是说,for 循环只是把与循环有关的代码集中在了一个位置。

3.6.5 for-in语句

for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。

for (property in expression) statement

for (var propName in window) {
    document.write(propName);
}

3.6.6 label语句

使用 label 语句可以在代码中添加标签,以便将来使用。以下是 label 语句的语法:

label: statement

var num = 0;
outermost:
for (var i=0; i < 10; i++) {
    for (var j=0; j < 10; j++) {
        if (i == 5 && j == 5) {
            continue outermost;
        }
        num++;
    }
}

这个例子中定义的 outermost 标签可以在将来由 break 或 continue 语句引用。加标签的语句一般都要与 for 语句等循环语句配合使用。

3.6.7 break和continue语句

break 语句会立即退出循环,强制继续执行循环后面的语句。而 continue 语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行。

3.6.8 with语句(不要用)

with 语句的作用是将代码的作用域设置到一个特定的对象中。

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
with(location){
    var qs = search.substring(1);
    var hostName = hostname;
    var url = href;
}

3.6.9 switch语句

switch 语句与 if 语句的关系最为密切,而且也是在其他语言中普遍使用的一种流控制语句。

常规用法:

switch (i) {
    case 25:
    /* 合并两种情形 */
    case 35:
        alert("25 or 35");
        break;
    case 45:
        alert("45");
        break;
    default:
        alert("Other");
}

与其他语言相比,switch语句中可以使用任何数据类型,每个case值也可以是变量,甚至是表达式。

switch ("hello world") {
    case "hello" + " world":
        alert("Greeting was found.");
        break;
    case "goodbye":
        alert("Closing was found.");
        break;
    default:
        alert("Unexpected message was found.");
}

以上代码结果就会显示"Greeting was found."。

注意:switch 语句在比较值时使用的是全等操作符,因此不会发生类型转换

3.7 函数

通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。

function functionName(arg0, arg1,...,argN) {
    statements
}

ECMAScript 中的函数在定义时不必指定是否返回值,未指定时返回值为undefined。

函数会在执行完 return 语句之后停止并立即退出

严格模式对函数有一些限制:

  • 不能把函数命名为 eval 或 arguments;
  • 不能把参数命名为 eval 或 arguments;
  • 不能出现两个命名参数同名的情况。

3.7.1 理解参数

arguments对象

ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。因为 ECMAScript 中的参数在内部是用一个数组来表示的。而在函数体内,我们就是通过arguments 对象来访问这个参数数组。

arguments对象是类数组。

ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的。

3.7.2 没有重载

什么是重载
方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。
什么是函数签名
定义函数接收的接受的参数的类型和数量

函数没有签名进而无法做到重载,所以ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数