ECMAScript作为核心,它规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、全局对象。
1.语法
ECMAScript 的语法很大程度上借鉴了 C 语言和其他类 C 语言,如 Java 和 Perl。
1.1区分大小写
首先要知道的是,ECMAScript 中一切都区分大小写。无论是变量、函数名还是操作符。
1.2标识符
所谓标识符,就是变量、函数、属性或函数参数的名称。标识符可以由一或多个下列字符组成:
第一个字符必须是一个字母、下划线(_)或美元符号($);
剩下的其他字符可以是字母、下划线、美元符号或数字。
注意第一个字符不能使数字
按照惯例,ECMAScript 标识符使用驼峰大小写形式,例如:
myCar, firstBook。
1.3注释
//单行注释
/*
这是多行注释
*/
2关键字与保留字
关键字=>js已经赋予特殊功能的单词。
如:
break、else、new、var、 case、 finally 、 return、 void 、 catch 、for 、switch 、 while 、 continue、 function 、this 、 with 、default 、 if 、 throw 、 delete 、 in 、 try 、do 、 instranceof、 typeof、let、const
保留字=>>js预订可能未来要使用的字。
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 变量
有三个关键字可以声明变量:var、let、const。var 在ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 及更晚的版本中使用。
3.1 var关键字
定义变量可以使用var操作符(var也是关键字),可以先声明再赋值,也能在声明的时候同时初始化。
var myFavorite;//默认undefin
myFavorite = 'book';//先声明再赋值
var myFavorite = 'book';//声明的时候同时初始化
随后,不仅可以改变保存的值,也可以改变值的类型:
myFavorite = 10;//10,但这么做并不推荐
3.1.1 var声明的作用域
var声明的作用域是函数作用域,使用 var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
function myTest(){
var a = 10;
console.log(a);//10,局部变量
}
console.log(a);//报错
省略var的话
function myTest(){
a = 10;
console.log(a);//10,全局变量
}
myTest();
console.log(a);//10
调用函数后啊才会在全局被定义。
可以一次性定义多个变量:
var a = 10,
b = 20,
c = 13;
3.1.2var 声明的提升
使用 var 时,下面的代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域.
顶部:
function myTest(){
console.log(a);
var a = 10;
}
myTest();//undefined
原因是为 ECMAScript 运行时把它看成等价于如下代码:
function myTest(){
var a ;
console.log(a);
var a = 10;
}
myTest();//undefined
3.2 let 声明
let 与var作用差不多都可以可以先声明再赋值,也能在声明的时候同时初始化。最明显的区别是,let 声明的范围是块作用域,而 var 声明的范围是函数作用域。
if(true) {
var a = 10;
console.log(a)//10
}
console.log(a);//10
用let的话
if(true) {
let a = 10;
console.log(a)//10
}
console.log(a);//报错
此外,使用let操作符的话同一个变量名不能重复声明。
var age;
var age;
let age;
let age;//SyntaxError,age已经用let声明过了。
JavaScript 引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同的标识符不会报错,而这是因为同一个块中没有重复声明:
var a = 20;
console.log(a);//20
if(true) {
var a = 10;
console.log(a)//10
}
var name= 'chen';
console.log(name);//chen
if(true) {
var name= 'li';
console.log(name)//'li'
}
对声明冗余报错不会因混用 let 和 var 而受影响。这两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在。(函数、块级)
var age;
let age;//报错
let age;
var age;//报错
3.2.1暂时性死区(temporal dead zone)
let 声明的变量不会在作用域中提升;
console.log(name);//chen
var name = 'chen';
console.log(name);// ReferenceError
let name = 'li';
3.2.2
与var 关键字不同,使用var在全局作用域中声明的变量会成为windo对象的属性,let不会:
var name = 'aa';
console.log(window.name);//aa
let name = 'bb';
console.log(window.name)//undefined
3.2.3for循环中的let
在 let 出现之前,for 循环定义的迭代变量会渗透到循环体外部:
for(var i = 0; i < 5; i++) {
}
console.log(i)//5
使用let就解决了这个问题
for(let i = 0; i < 5; i++) {
}
console.log(i)//ReferenceError:
3.3 const声明
const与let基本一致,但在声明的时候必须进行初始化,且不能修改const声明的变量;
const pig;//报错
const age = 17;
age = 18;//TypeError,给常量赋值;
也不允许重复声明
const Test = 'book';
const Test = 'English';//SyntaxError
const声明的作用域也是块
if(true) {
const color = 'red';//red
console.log(color)
}
console.log(color)//ReferenceError
const声明的限制只是对于它指向的变量;如果声明的是一个对象,那么这个对象依旧是可修改的。
const o = {};
o.name = 'chen';//'chen'
既然这样就好理解接下来在for循环中用const声明了。
for(const j = 0; j < 10; j++){}//TypeError
这是因为迭代变量会自增。
如果这样就没问题了.
let i = 0;
for(const j = 7; i < 5; i++) {
console.log(j)//7,7,7,7,7
}
此外,
for(const key in {a:1, b: 2}) { , ;/
console.log(key)//a,b
}
for(const key in [1,2,3]) {
console.log(key)//0,1,2
}
这样是可行的,数组也是对象的一种。
3.4数据类型
ECMAScript 有六种基本数据类型(简单数据类型):
"undefined"表示值未定义;
"boolean"表示值为布尔值;
"string"表示值为字符串;
"number"表示值为数值;
"object"表示值为对象(而不是函数)或 null;
"function"表示值为函数;
"symbol"表示值为符号。
还有引用数据类型(复杂数据类型)Object。
3.4.1typeof
可以通过typeof来检测数据类型。比如:
typeof 123;//"number"
typeof '123'//"string"
typeof 的返回值是字符串;
3.4.2 undefined
undefined类型只有一个值就是undefined。
当使用var或let声明变量却没有初始化时,相当于给变量复制了undefined。
let message;//undefined
var information;//undefined
但是,声明还是没声明调用typeof都会返回undefined。
let un;
console.log(un); //undefined
console.log(age); //报错
typeof un; //undefined
typeof age; //undefined
建议在声明变量的同时进行初始化(比如let num = 10)。这样,当 typeof 返回"undefined"时,你就会知道那是因为给定的变量尚未声明(也就是啥都没做),而不是声明了但未初始化。
3.4.3 null
Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给typeof 传一个 null 会返回"object"的原因:
typeof null; //'object'
null == undefined; //true
任何时候,只要变量要保存对象,而当时又没有那个对象可保存,就要用 null 来填充该变量。这样就可以保持 null 是空对象指针的语义,并进一步将其与 undefined 区分开来。
3.4.4 Boolean
有两个字面值:true 和 false。
布尔值字面量 true 和 false 是区分大小写的,因此 True 和 False(及其他大小混写形式)是有效的标识符,但不是布尔值。
let true; // SyntaxError
let True; //undefined
此外,
let message = "Hello world!";
let messageAsBoolean = Boolean(message); //true
字符串 message 会被转换为布尔值并保存在变量 messageAsBoolean 中。
什么值能转换为 true或 false?
当转换的值是 ' '(空字符串)、NaN、null、false、undefined、0这六种情况下时为假值(false);其他情况均为true。
ps: Boolean([]) == true;
3.4.5 Number
整数也可以用八进制(以 8 为基数)或十六进制(以 16 为基数)字面量表示。
对于八进制字面量,第一个数字必须是零(0),第二位可以是 o 或者 O(可以省略);然后是相应的八进制数字(数值 0~7)。
let octalNum1 = 070; //8
let octalNum2 = 0o70; //8
let octalNum3 = 0O70; //8
要创建十六进制字面量,必须让真正的数值前缀 0x或0X,然后是十六进制数字(0~9 以及 A~F(a-f));
let hexNum1 = 0xA; // 十六进制 10
let hexNum2 = 0XA; // 十六进制 10
let hexNum3 = 0xa; // 十六进制 10
1.NaN;(not a number)
在 ECMAScript 中,0、+0 或0 相除会返回 NaN:
console.log(0/0); // NaN
console.log(-0/+0); // NaN
如果分子是非 0 值,分母是有符号 0 或无符号 0
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
NaN不等于本身
console.log(NaN == NaN); // false
isNaN()接受一个参数并判断其是否“不是数值”
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
- 数值转换
string "13px" => NaN; " " => 0
boolean true => 1 false => 0
null null => 0
undefined undefined => NaN
{} {} => NaN
[] [1]=>1,[]=>0,[1,2]=>NaN
function Number(function(){}) => NaN
parseInt方法
调用parseInt(),字符串最前面的空格会被忽略,从第一个非空格字符开始转换。如果第一个字符不是数值字符、加号或减号,parseInt()立即返回 NaN。
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
也可以接受第二个参数
let num = parseInt("0xAF", 16); // 175
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
发现跟直接写
let num = 0xAF;//175
一样。
但是第一个参数可以直接传值;
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
parseFloat
parseFloat()函数的工作方式跟 parseInt()函数类似,但是只解析到一个小数点而第二个小数点后的数值会被省略,此外,parseFloat()只解析十进制。
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
3.4.6 String
ECMAScript 中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。
转换为字符串
1 、toString()
let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); // 字符串"true"
在对数值调用这个方法时,toString()可以接收一个底数参数,即以什么底数来输出数值的字符串表示。
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
2、String()
String()函数遵循如下规则。
如果值有 toString()方法,则调用该方法(不传参数)并返回结果。
如果值是 null,返回"null"。
如果值是 undefined,返回"undefined"。
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
3.4.7 Symbol
3.4.8Object
这两个后面单独写吧