语法
以下是js的语法要求
- 大小写敏感
- 标识符: 即我们说的变量名 开头必须是字幕/下划线/&的一种
- 不能把关键字/保留字/true,false,null作为标识符
- 注释:
- 单行注销: //
- 多行注销: / here is your code /
- 严格模式: Es5引入严格模式,在严格模式下,ECMAScript 3 中的一些不确定的行为将得到处理,而且对某些不安全的操作也会抛出错误。
- 语法: 在顶部 添加
"use strict";
即可
- 语法: 在顶部 添加
- 语句: 建议每一行语句背后加分号, 哪怕这不是必须的-因为解释器会自行补充 , 不过这样会耗费时间和性能.
关键字和保留字
Reserved Words - JavaScript | MDN 可以查看最新的关键字和保留字
以上都是不能作为标识符的.
变量
js声明变量的方式如下
var message; // 松散型变量, 你可以赋任何值, 如果不显示赋值, 默认值为undefined
我们看一个例子:
var message = 'hi';
message = 10;
虽然我们声明了一个名为message的变量, 但并不意味着它就是字符串类型.
再看一个例子:
function test(){
var message = 'hi';
}
test();
alert(message) // Uncaught ReferenceError: message is not defined
上面的实例说明了用var定义的变量, 将会成为当前作用于的局部变量, 通常外部无法访问.
实际上不用var也能直接声明一个变量:
function test(){
message = "hi"; // 挂载到全局
}
test();
alert(message); // "hi"
数据类型
Es中有6种数据类型, 实际上到现在为止(2019)有7种, 不过此系列文章讨论ES5.
基本数据类型:
- Undefined
- Null
- Boolean
- Number
- String
复杂数据类型:
- Object: 数组, 函数, 对象都统称为Object类型
typeof 操作符
js中, 给定任意一个变量, 用typeof操作符去检验, 必然返回以下结果之一:
- undefined
- boolean
- string
- number
- object
- function
Undefined类型
Undefined 类型只有一个值,即特殊的 undefined。在使用 var 声明变量但未对其加以初始化时, 这个变量的值就是 undefined
Null类型
Null 类型是第二个只有一个值的数据类型,这个特殊的值是 null。从逻辑角度来看,null 值表示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回”object”的原因
实际上 undefined是派生于null
undefined == null; // true
Boolean类型
Boolean 类型是 ECMAScript 中使用得最多的一种类型,该类型只有两个字面值:true 和 false。
一个变量想得到对应的Boolean值, 可调用Boolean()函数
对于一个变量s, 如果它满足以下条件之一, Boolean(s)就返回false:
- Boolean: false
- String: 空字符串
- Number: 0和NaN
- Object: null
- Undefined: undefined
Number类型
Number类型要注意几个关键点:
- 浮点数精度问题: 如 0.1+0.2 != 0.3
- 以0开头八进制数字赋值时的差异: 比如 var num1 = 070, num2 = 071; 表现不一致
- 科学计数法
- 数值范围有限
- NaN: NaN != NaN
- 数值转换, 有三个能把非数值转换成数值的方法:
- Number()
- parseInt(arg1,arg2) //parseInt(“AF”, 16); 转换成10进制
- parseFloat()
String类型
这是一个拥有属性
的基本类型(实际上数值, 布尔值, 对象和字符串值都有toString方法 ,后面的章节复习中会讲到包装类型)
var str = 'hello';
alert(str.length); //6
字符字面量: 保留了一些\n
,\t
,\b
,\r
等转义序列, 用于表示非打印字符.
拼接字符串效率问题?
var lang = "Java";
lang = lang + "Script";
以上示例中的变量 lang 开始时包含字符串”Java”。而第二行代码把 lang 的值重新定义为”Java” 与”Script”的组合,即”JavaScript”。实现这个操作的过程如下:
- 首先创建一个能容纳 10 个字符的新字符串
- 然后在这个字符串中填充”Java”和”Script”
- 最后一步是销毁原来的字符串”Java”和字符串”Script”
以上是旧浏览器(例如版本低于 1.0 的 Firefox、IE6 等)存在的问题, 目前的浏览器已经不存在字符串拼接效率问题, 所以请大胆使用.
把其他数据类型(不含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(): 可以转换null和undefined
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1)); // "10"
alert(String(value2)); // "true"
alert(String(value3)); // "null"
alert(String(value4)); // "undefined"
Object类型
创建Object对象实例通常方法:
- 构造函数:
var obj1 = new Object; // 没有参数是可以省略括号的
- 对象字面量
var obj2 = { };
Object 的每个实例都具有下列属性和方法。
- constructor:保存若用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor)就 是 Object()。
- hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如:o.hasOwnProperty(“name”))。
- isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原型)。
- propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语旬(本章后面将会讨论)来枚举。与 hasOwnProperty()方法一样,作为参数的属性名必须以字符串形式指定。
- toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
- toString():返回对象的字符串表示。
- valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值相同。
由于在 ECMAScript 中 Object 是所有对象的基础,因此所有对象都具有这些基本的属性和方法。
操作符
开始之前, 我们来看看一道题:
var a = 1, b = 2, c = 3, d=4;
var e1 = a<b || b>c && c<d || d<a; //?
var e2 = a<b && b>c || c<d && d<a; //?
所以e1 , e2到底是true还是false呢? 这里就涉及到操作符优先级的问题
一元操作符
只能操作一个值的符号就叫做一元操作符, 也是ES里面最简单的操作符
自增自减操作符
递增和递减操作符, 其中又分前置和后置的情况, 我们看两个有意思的例子:
前置:
var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2; // 等 于 21
var num4 = num1 + num2; // 等 于 21
后置:
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; // 等 于 22 , num1的值是计算完num3之后再修改的
var num4 = num1 + num2; // 等 于 21
对于这种蛋疼的现象(计算机中称为副效应), 我们可以这么记忆:
在运算时, 前置先修改(因为前置的优先级和执行语句的优先级相等), 后置后修改 (笑)
自增自减符, 对于任何值都适用:
- 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字符串变量变成数值变量。
- 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN(第 4 章将详细讨论)。字符串变量变成数值变量。
- 在应用于布尔值 false 时,先将其转换为 0 再执行加减 1 的操作。布尔值变量变成数值变量。
- 在应用于布尔值 true 时,先将其转换为 1 再执行加减 1 的操作。布尔值变量变成数值变量。
- 在应用于浮点数值时,执行加减 1 的操作。
- 在应用于对象时,先调用对象的 valueOf()方法(第 5 章将详细讨论)以取得一个可供操作的值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规则。对象变量变成数值变量。
这里是一些示例:
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(由于浮点舍入错误所致)
o--; // 值变成数值-2
加减操作符
略
位操作符
讲这个之前, 自行了解下一下二进制码, 反码, 补码的概念. 可以点击此处查看相关内容, 我这里只简单说说
我们首先记住一个规定(反正是计算机科学家规定的):
用32为的二进制数才存储数值 , 从右往左开始, 为第1位到第32位, 第32位是用来做符号位,
0
表示正数,1
表示负数.
正数以纯二进制格式存储.
如18这个十进制数:
它的二进制数表示为: 10010
至于-18, 则用经过三个计算步骤用补码表示:
- 计算该数绝对值的二进制码:
00000000 00000000 00000000 00010010
- 求反:
11111111 11111111 11111111 11101101
- 反码加1:
11111111 11111111 11111111 11101110
所以 -18 的二进制表示是: 11111111 11111111 11111111 11101110
你可能看到这里头都大了, 为啥看起来这么复杂, 那我们就来讨论一下这个问题, 这回我们不用32位的二进制数, 我们用8位二进制数来做demo:
8位二进制数, 如果只用来表示正数 那么:
- 最小值: 0000 0000
- 最大值: 1111 1111
看着没毛病
但是要表示正负数, 并且计算基只认识0和1, 那我们只好用第8位来做符号位 :
- 非负数数值范围: [0000 0000, 0111 1111], 也就是[0,127]
- 负数范围: [1000 0000, 11111111], 也就是[0,-127]
根据常识, 一个正数要加上另一个数字等于0 , 那么这个数字肯定是它的相反数
比如 1+(-1) = 0
我们再回到八位二进制数:
1表示成: 0000 0001
-1表示成: 1000 0001
(我知道长这样它才是你心目中的-1
)
那么: 0000 0001 + 1000 0001 = 1000 0010
显然1000 0010长得又不像你心目中的0(实际上也不是)
我们假设: 0000 0001+ x = 0000 0000 (注意这里并不是1000 0000)
得到x = 1111 1111 也就是-1
此处参考了 wenxinwukui234的博客
实际上
0000 0001+ 1111 1111 = 1 0000 0000
产生了溢出问题
但是根据前面计算补码的规则:
绝对值: 0000 0001
求反: 1111 1110
加一: 1111 1111 (和我们之前计算的一致)
- 非(NOT): ~ , 求反码
- 与(AND): & , 二进制同时有1才取1
- 或(OR): | , 二进制有1取1
- 按位异或(XOR): ^ , 二进制相同的数取0 , 不同则取1
- 左移:<<
- 右移:>>
布尔操作符
- 逻辑非(!)
- 逻辑与(&)
- 逻辑或(||)
乘性操作符
- 乘法(*)
- 除法(/)
- 求模(%)
加性操作符
- 加法(+): 数值 + 字符串 == 字符串
- 减法(-): 数值 - 字符串 == 数值
关系操作符
字符串比较大小的时候, 是比较字符编码位置的大小 , 如果是对象比较, 会先调用valueOf方法, 如果没有valueOf方法, 就调用toString方法
- 大于(>)
- 小于(>)
相等操作符
以下的操作符会进行强制类型转换, 再比较相等性
- 相等(==)
- 不相等(!=)
在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
- 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值 false 转换为 0,而true 转换为 1;
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较
- null == undefined
- NaN != NaN
- 对象和对象的相等检测, 会判断是不是指向同一个对象
- 全等(===) : 不会进行强制类型转换
条件操作符
也就是通常我们所说的三元操作符: var s = bool? true : false;
赋值操作符
以下是常见的赋值操作符, 不过使用这些并不会带来性能上的提升, 取决于你的爱好
- +=
- -=
- *=
- /=
- %=
- <<=
=
逗号操作符
只需要记住
- var num1=1, num2=2, num3=3; // 声明变量时候的简约方式
- var num = (5, 1, 4, 8, 0); // num 的值为 0
语句
if语句
略
do-while语句
do-while循环至少会执行一次
while语句
略
for语句
略
for-in语句
for-in 语旬是一种精准的迭代语旬,可以用来枚举对象的属性。
以下是 for-in 语旬的语法:
for (var propName in window) {
console.log(propName);
}
在这个例子中,我们使用 for-in 循环来显示了 BOM 中 window 对象的所有属性。每次执行循环时,都会将 window 对象中存在的一个属性名赋值给变量 propName。这个过程会一直持续到对象中的所有属性都被枚举一遍为止。
与 for 语旬类似,这里控制语旬中的 var 操作符也不是必需的。但是, 为了保证使用局部变量,我们推荐上面例子中的这种做法。
ECMAScript 对象的属性没有顺序。因此,通过 for-in 循环输出的属性名的顺序是不可预测的。具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。但是,如果表示要迭代的对象的变量值为 null 或 undefined,for-in 语旬会抛出错误, ECMAScript 5 更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。
label语句
不建议使用
break和continue语句
不建议使用
with语句
不建议使用, 会改变上下文环境, 而且有性能问题
switch语句
如果你的if..else if..不合理, 那需要考虑用这个
函数
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语旬,而且可以在任何地方、任何时候调用执行。ECMAScript 中的函数使用 function 关键字来声明,后跟一组参数以及函数体。
以下是一个函数示例:
function sayHi(name, message) {
alert("Hello " + name + "," + message);
//return ; //不必指定是否有返回值
}
理解参数
你可以传无限个参数, 也不介意你的参数是什么类型, 因为函数内部有一个叫arguments的类数组对象( arguments instanceof Array == false)
我们来看一个例子:
function doAdd(num1, num2) {
arguments[1] = 10;
console.log(arguments[0] + num2);
}
doAdd(10); //NaN , 说明形参和arguments[n]都是独立的, 但是值会根据实参同步个数
doAdd(10,0); // 20
没有重载
ES没有重载, 但是可以通过判断参数的长度来模拟