语法
ECMAScript中的一切(变量、函数名和操作符)都区分大小写
关键字也区分大小写
typeof是关键字,不能作为变量名,但typeOf是可以的
严格模式
在严格模式下,ECMAScript 3中的一些不确定的行为将得到处理,而且对某些不安全 的操作也会抛出错误。要在整个脚本中启用严格模式,可以在顶部添加如下代码:"use strict";
在函数内部的上方包含这条编译指示,也可以指定函数在严格模式下执行:
function doSomething(){
"use strict";
//函数体
}
js语句结尾要不要加分号?
只有(),[],+,-,正则在行首的时候,上一行加不加分号会引起歧义,其中一般+,-,正则都不会在行首出现
结论:主要看习惯,推荐不加,然后在出现()和[]时,在行首加一个分号
;(function (){
console.log('自调用函数行首加;')
})()
关键字和保留字 (ES3)
关键字
具有特定用途的关键字,这些关键字可用于表示控制语句的开始或结束,或 者用于执行特定操作等。
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
奇怪点:用let作为变量名时不会报错
var let = 4
console.log(let) //4
非严格模式下可以,严格模式下会报错SyntaxError: Unexpected strict mode reserved word
第 5版把在非严格模式下运行时的保留字缩减为下列这些:
class | enum | extends | super const | export | import
在严格模式下,第 5版还对以下保留字施加了限制:
implements | package | public | interface | private | static | let protected | yield
变量
可以在修改变量值的同时修改值的类型
var message = "hi";
message = 100; // 有效,但不推荐
如果在函数中使用 var 定义一个变量,那么这个变量在函数退出后就会被销毁
省略 var 操作符,可以创建一个全局变量
function test(){
message = "hi"; // 全局变量
}
test();
alert(message); // "hi"
只要调用过一次 test()函 数,这个变量就有了定义,就可以在函数外部的任何地方被访问到。
虽然可以,但不推荐这样做,给未经声明的变量赋值在严格模式 下会导致抛出 ReferenceError 错误。
数据类型
基本数据类型:Undefined、Null、Boolean、Number 和String。
复杂数据类型——Object
typeof操作符
- “undefined”——如果这个值未定义;
- “boolean”——如果这个值是布尔值;
- “string”——如果这个值是字符串;
- “number”——如果这个值是数值;
- “object”——如果这个值是对象或 null;
- “function”——如果这个值是函数。
特殊值 null 被认为是一个空的对象引用
Undefined类型
- 未经初始 化的值默认就会取得 undefined 值
- undefined 值是为了正式区分空对象指针(null)与未经初始化的变量
- 包含 undefined 值的变量与尚未定义的变量还是不一样的
var message; // 这个变量声明之后默认取得了 undefined 值
// 下面这个变量并没有声明var age
alert(message); // "undefined"
alert(age); // 产生错误
- 对于尚未声明过的变量,只 能执行一项操作,即使用 typeof 操作符检测其数据类型
- 对未初始化和未声明的变量执行 typeof 操作符都返回了 undefined 值
- 没有必要把一个变量的值显式地设置为 undefined
Null类型
- null 值表 示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回"object"的原因
- 如果定义的变量准备在将来用于保存对象,那么好将该变量初始化为 null 而不是其他值
Boolean类型
- Boolean 类型的字面值 true 和 false 是区分大小写的。也就是说,True 和 False (以及其他的混合大小写形式)都不是 Boolean 值,只是标识符
- ECMAScript中所有类型的值都有与这两个 Boolean 值等价的值。要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolean()
- 可以对任何数据类型的值调用 Boolean()函数,而且总会返回一个 Boolean 值。
所以if()语句里写啥都可以转换,不会报错
Number类型
- 除了以十进制表示外,整数还可以通过八进制(以 8为基数)或十六进制(以 16 为基数)的字面值 来表示
- 八进制字面值的第一位必须是零(0)
- 十六进制字面值的前两位必须是 0x,字母 A~F 可以大写,也可以小写
- 可以保存正零(+0)和负零(0)。正零和 负零被认为相等
- 如果小数点后面没有跟任何数字,那么这个数值就可以作为整数值来保存*(浮点数占内存是整数的两倍)*
- 如果浮点数值本身表示的就是一个整数(如1.0),那么该值也会被转换为整数*(节省内存)*
- 科学计数法e的大小写都可以使用
永远不要测试某个特定的浮点数值
不要对浮点数做或者=操作,如果想测试某个数值是不是等于一个特定的浮点数,可以使用他们之差的绝对值小于js中的最小值epsilon的方法
js中存在最大值Number.MAX_VALUE 和最小值Number.MIN_VALUE ,如果超出范围就会转换成无穷Infinity ,有正无穷和负无穷
- Infinity 不是能够参与计算的数值。
- 要想确定一个数值是不是有穷的(换句话说,是不是位于 小和大的数值之间),可以使用 isFinite()函数。这个函数在参数位于小与大数值之间时会返 回 true
- 只有 0除以0才会返回 NaN,正数除以 0返回 Infinity,负数除以 0返回-Infinity
- 任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN
- NaN 与任何值都不相等,包括 NaN 本身
Number()、parseInt()和 parseFloat()
- Number()可以用于任何数据类型。
- parseInt()和 parseFloat()则专门用于把字符串转换成数值。
parseInt()会从第一个非空格字符开始解析,直到遇到非数字字符结束,返回解析过的数字,自动去除前面的数字前的0。如果第一个字符就不是数字,则直接返回NaN。空字符串也会返回NaN。
如果字符串以"0x"开头且后跟数字字符,就会将其当作一 个十六进制整数;
但如果字符串以"0"开头且后跟数字字符,则不会将其当作一个八进制数来解析
parseInt()函数提供第二个参数:转换 时使用的基数(即多少进制)
var num = parseInt("0xAF"); //175
var num1 = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN
为了避免错误的解析,建议无论在什么情况下都明确指定基数
parseFloat()和 parseInt()类似,只不过可以解析小数点
字符串中的第 一个小数点是有效的,而第二个小数点就是无效的了
- parseFloat()只解析10进制数,十六进制格 式的字符串则始终会被转换成 0
- parseFloat()没有用第二个参数指定基数的用法
String类型
- 转义
\n 换行 \t 制表 \b 空格 \r 回车 \ 斜杠
转义序列表示 1个字符,空格也是一个字符
console.log('a \r c'.length); //5
拼接字符串
- 字符串一旦创建,它们的值就不能改变,只能通过赋值新的字符串,销毁旧的字符串的方式。
var lang = "Java";
lang = lang + "Script";
首先创建一个能容纳 10个字符的新字符串,然后在这个字符串中填充"Java"和"Script",后一步是销毁原来的字符串"Java"和字 符串"Script",因为这两个字符串已经没用了
转换字符串
toString()方法:基本除了 null 和 undefined 值没有这个方法外,其他值都有这个方法。
- 在调用数值的 toString()方法时,可以传递一个参数:输出数值的基数,使之转化为对应进制的字符串
String()函数能够将任何类型的值转换为字符串
- 如果值是 null,则返回"null";
- 如果值是 undefined,则返回"undefined"。
- 其他值会找它的toString()方法
Object类型
对象其实就是一组数据和功能的集合。对象可以通过执行 new 操作符后跟要创建 的对象类型的名称来创建。
Object 的每个实例都具有下列属性和方法:
- constructor:保存着用于创建当前对象的函数。
- hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例 的原型中)是否存在。
- isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型
- propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句来枚举。
- toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
- toString():返回对象的字符串表示
- valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值相同
操作符
一元操作符
只能操作一个值的操作符叫做一元操作符
++a | --a | a++ | a–
前置操作符先计算赋值后,再进行其他计算
后置操作符先进行其他计算,再进行重新赋值
- 所有这 4个操作符对任何值都适用,也就是它们不仅适用于整数,还可以用于字符串、布尔值、浮 点数值和对象。
- 对于非数值对象,先执行类型转换为数值类型,再进行加减操作,最后返回数值类型
一元加减操作符
+a | -a
- 在对非数值应用一元加操作符(+)时,该操作符会像 Number()转型函数一样对这个值执行转换
- 一元减操作符(-)应用于数值时,该值会变成负数
- 一元减操作符(-)应用于非数值时, 一元减操作符遵循与一元加操作符相同的规则,后再将得到的数值转换为负数
位操作符
数字由32位2进制数保存,正数取负,是求对应的补码(反码加一)
- 按位非(NOT)~
执行按位非的结果就是返回数值的反码
也就是对应负数再减一
console.log(~25); //26
console.log(~-25); //24
按位非是在数值表示的底层执行操作,因此速度更快
- 按位与(AND) &
按位与操作就是将两个数值的每一位对齐,对相同位置上的两个数执行 AND(有0为0,全1为1)操作,返回数值类型
console.log(25 & 3); //1
console.log(25 & 24); //24
console.log(25 & true); //1
console.log(25 & false); //0
- 按位或(OR) |
按位或操作就是将两个数值的每一位对齐,对相同位置上的两个数执行 OR(有1为1,全0为0)操作,返回数值类型 - 按位异或(XOR) ^
按位异或操作符由一个插入符号(^)表示,按位异或操作就是将两个数值的每一位对齐,对相同位置上的两个数执行 XOR操作(相同为0,不同为1),返回数值类型 - 左移 <<
左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数,右边用0补齐
数值 2(二进制码为 10)向左移动 5位,结果就是 64(二进制码为 1000000)
左移不会影响操作数的符号位 - 有符号的右移 >>
有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位,用符号位的值来填充左侧空位 - 无符号右移 >>>
无符号右移操作符由 3个大于号(>>>)表示,这个操作符会将数值的所有 32位都向右移动,无符号右移是以 0来填充空位
对正数的无符号右移与有符号右移结果相同,但对负数的结果就不一样了
布尔操作符
- 逻辑非 !
逻辑非操作符由一个叹号(!)表示,可以应用于 ECMAScript中的任何值。无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反
同时使用两个逻辑非操作符,实际上就会模拟 Boolean()转型函数的行为
- 逻辑与 &&
逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。在有一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值
如果第一个操作数是对象,则返回第二个操作数(或第二个对象)
如果只有第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该 对象;
如果有null,NaN,undefined,则返回对应的这三个值
不能在逻辑与操作中计算未定义的值
- 逻辑或 ||
逻辑或操作符也是短路操作符
返回第一个对象,第一个为false才返回第二个操作数
乘性操作符 (乘法、除法和求模)
- 乘法
如果是 Infinity 与 0相乘,则结果是 NaN - 除法
如果是 Infinity 被 Infinity 除,则结果是 NaN
如果是零被零除,则结果是 NaN
如果是 Infinity 被任何值除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号 - 求模
如果被除数是无穷大值,则结果是 NaN;
如果被除数是有限大的数值而除数是零,则结果是 NaN;
如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
加性操作符
- 加法
如果是 Infinity 加-Infinity,则结果是 NaN;
如果是+0加-0,则结果是+0
如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值,然后进行字符串拼接 - 减法
如果是 Infinity 减 Infinity,则结果是 NaN;
如果是-Infinity 减-Infinity,则结果是 NaN;
如果是+0减+0,则结果是+0
如果是+0减-0,则结果是-0;
如果是-0减-0,则结果是+0
如果有一个操作数是字符串、布尔值、null 或 undefined,则先在后台调用 Number()函数将 其转换为数值,然后再根据前面的规则执行减法计算
如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值
+是转字符串,-是转数字
关系操作符
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)
如果两个操作数都是字符串,则比较两个字符串第一个字符对应的字符编码值(a<z)(数字<大写<小写)
NaN和谁比都是false
除了两个都是字符串,不是数字的话就都转数字,按数字比较
相等操作符
- == 和 !=
相等和不相等——先转换再比较
如果有布尔就都转布尔
如果是字符串和数字,都转数字
一个是对象,另一个不是,则对象转valueOf()
如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true
两个操作数指向同一个对象为true,否则false - === 和 !==
全等和不 全等——仅比较而不转换
先比类型,再比数值
条件操作符 ?
会将条件部分用Boolean()函数包裹,和if()相同
逗号操作符
使用逗号操作符可以在一条语句中执行多个操作var num1=1, num2=2, num3=3;
在用于赋值时,逗号 操作符总会返回表达式中的后一项var num = (5, 1, 4, 8, 0); // num 的值为 0
语句
for-in语句
for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性
for(let a in obj){
//这里使用a可以代表obj里的每个属性名
}
通过 for-in 循环输出的属性名的顺序是不可预测的。 具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。
label语句
标记语句可以和 break 或 continue 语句一起使用。标记就是在一条语句前面加个可以引用的标识符(identifier)。
- 在 for 循环中使用带标记的 continue 语句
var i, j;
loop1:
for (i = 0; i < 3; i++) { //The first for statement is labeled "loop1"
loop2:
for (j = 0; j < 3; j++) { //The second for statement is labeled "loop2"
if (i === 1 && j === 1) {
continue loop1;
}
console.log('i = ' + i + ', j = ' + j);
}
}
// Output is:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// 注意观察是如何跳过输出 "i = 1, j = 1" and "i = 1, j = 2"
- 在 for 循环中使用带标记的 break
var i, j;
loop1:
for (i = 0; i < 3; i++) { //The first for statement is labeled "loop1"
loop2:
for (j = 0; j < 3; j++) { //The second for statement is labeled "loop2"
if (i == 1 && j == 1) {
break loop1;
}
console.log("i = " + i + ", j = " + j);
}
}
// Output is:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
**优点:**可以手动控制循环,多层循环嵌套时,在内层可以直接用一个break或者continue控制外层的循环
**注意:**不能对函数声明进行标记
with语句
- 定义 with 语句的目的主要是为了简化多次编写同一个对象的工作
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
// 使用with语句简化
with(location){
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
- with有性能和兼容性问题
- with在ES5严格模式中会报错
- with有可能会产生歧义
不要用with
break和continue语句
- 可以使用标签控制跳出位置
- outermost 标签表示外部的 for 语句
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++;
}
}
alert(num); //95
switch语句
- 可以在 switch 语句中使用任何数据类型,无论是字符串,还是对象,甚至是计算表达式都没有问题。
function sw(a){
switch(a){
case 1+2:
console.log(a);
break;
case 'hi' :
console.log(a)
break;
case 'hello' + 'world':
console.log(a)
break;
default:
console.log('anything' + a);
}
}
sw(1+1+1) //3
sw('hi') //'hi'
sw('helloworld') //helloworld
sw([1,2,3]) //anything1,2,3
sw({name:'obj'}) //anything[object Object]
- switch 语句在比较值时使用的是全等操作符,因此不会发生类型转换(例如, 字符串"10"不等于数值 10)
- switch适合作为多分枝语句方法代替多个if()语句
var num = 25;
switch (true) {
case num < 0:
console.log("Less than 0.");
break;
case num >= 0 && num <= 10:
console.log("Between 0 and 10.");
break;
case num > 10 && num <= 20:
console.log("Between 10 and 20.");
break;
default:
console.log("More than 20.");
}
// More than 20.
函数
- return 语句也可以不带有任何返回值。在这种情况下,函数在停止执行后将返回 undefined 值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下
- 推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。 一个函数尽量不要有多个返回值
理解参数
- arguments 对象只是与数组类似(它并不是 Array 的实例)
- 命名的参数只提供便利,但不是必需的
function sayHi() {
console.log("Hello " + arguments[0] + "," + arguments[1]);
} //形参只是为了方便使用,不是必要的
sayHi('Tony','how are you?') //Hello Tony,how are you?
- arguments 对象可以与命名参数一起使用
- arguments的值永远与对应命名参数的值保持同步,修改其中一个,另一个也就相应发生改变,虽然它们的值会同步,但它们的内存空间是独立的。
- arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名 参数的个数决定的
- 形参只是对arguments的包装,函数参数还是要以arguments为准
没有重载
**重载:**函数同名不同参数,执行不同方法,js没有重载,因为参数可以随便给
- 如果在 ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数