语法
标识符
标识符是变量,函数,属性的名字。标识符规则,首先是区分大小写。第一个字符必须是一个字母,下划线或美元。其他字符可以是字母,下划线,美元和数字。
变量
定义变量时要使用var标识符
var message;
var message = "hi";
message = 100;
在JS中,变量可以保存任何类型的值,但是并不推荐这么做。
要注意的是,使用var定义的变量会成为定义这个变量的作用域中的局部变量。
如果你不使用var关键字直接定义并赋值一个变量,这个变量会自己变成一个全局变量。当然,全局变量并不 是一个好东西。
function test(){
message = "hi";
}
test();
alert(message);
数据类型
5种基本数据类型Undefined,Null,Boolean,Number,String。1种复杂类型Object(本质上为无序的键值对)。不支持创建自定义数据类型。
typeof
因为JS是弱类型的,所以有一种方法来检查变量是什么类型的就显得很重要了。
typeof是一个操作符,并不是一个函数,所以并不用写参数的括号。
var message = "some string";
alert(typeof message);
typeof会返回以下值:
- undefined 这个值未定义
- boolean � 这个值是布尔
- string 这个值是字符串
- number 是数值
- object 这个值是对象或null
- function 这个值是函数
null会被认为是一个object是因为它被认为是一个空对象的引用。严格来讲function在JS中是一个对象,但是因为他比较特殊,所以把他单放出来。
Undefined
undefined代表的是声明了但是没有定义的变量,与没有声明的变量是有显著区别的。但是typeof他们都会返回undefined。
var message;
// var age
alert(message); // "undefined"
alert(age); // 报错
alert(typeof message); // "undefined"
alert(typeof age); // "undefined"
Null
null和undefined有很多相似的地方,事实上undefined是派生自null的。
alert(null == undefined); //true
不过null和undefined在逻辑和使用上是有着本质的不同的。你永远不需要吧一个变量赋值为undefined,但是在你创建了一个用于保存一个对象的变量的时候,你可以把他初始化为null,这样就可以判断这个变量是否真正保存了你想要的对象,这也正是null作为空对象指针的用处。
Boolean
这个没啥好说的,注意每种数据类型都有与之对应的Boolean值就好,判断什么的用的上。
Number
number类型可以用来表示整数和浮点数
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; // 这样的写法可以但是不推荐
var floatNum2 = 10.0; //这样会存为整数而不是浮点数
var floatNum = 3.125e7 //31250000
浮点数计算的结果是不精确的,比如0.1+0.2=0.30000000000000004所以永远不要测试浮点数计算的结果。
JS可以保存的数值是有范围的,存在Number.MIN_VALUE和Number.MAX_VALUE 中,超过范围的值会被转换成+/-Infinity,不能参与下次的计算,可以用isFinite()来判断一个数是否超出范围。
NaN
这是一个神奇的东西,这个数值表示一个本来要返回数值的操作数但并未返回数值的情况,例如任何数除以0就回返回NaN。NaN的两个特点:涉及NaN的任何操作都会返回NaN,NaN与任何值都不相等,包括NaN自己。
isNaN()用来判断任何类型的参数是否可以转换为数值。不能则返回true
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false
alert(isNaN("10")); //false
alert(isNaN("blue")); //true
alert(isNaN(true)); //false
数值转换
Number()、parseInt()、parseFloat()可以用来将非数值转换为数值。后两个专门用于将字符串转换为数值。而第一个则可以用于任何数据类型。具体的规则比较多,但都是很合理的可以自己yy出来。注意16进制的字符串它可以识别出来并转化为十进制输出。举几个例子:
var num1
= Number("1234Hello"); //NaN
var num2
= Number(""); //0
var num3
= Number("000011"); //11
var num4 = Number(true); //1
parseInt()的规则有些不一样:
var num1 = parseInt("1234blue");
// 1234
var num2 = parseInt("");
// NaN
var num3 = parseInt("0xA",16);
// 10十六进制
var num4 = parseInt(22.5);// 22
var num5 = parseInt("070",8);
// 56 八进制
var num6 = parseInt("70");
// 70
var num7 = parseInt("0xf");
// 15
第二个参数是基数,建议在任何情况下都指定,这样比较保险,一般就是10。
parseFloat()只有第一个小数点有效。且只认十进制,忽略先导0。
String
\xnn:代表以十六进制代码nn表示的一个字符,例如\x41表示A
\unnnn:代表以十六进制代码nnnn表示的Unicode字符
以上这两个在使用.length方法时会被视为一个字符。但是如果包含双字节字符就可能会出错,这点就没有swift智能哈哈哈啊哈。
字符串是不可变的,要改变某个变量保存的字符串,首先要销毁原字符串,再用另一个新的字符串填充新的
几乎每个值都有toString()方法将自己转换为字符串。但是null和undefined没有这个方法。在你不知道变量会不会是null时可以使用String()这个方法把任何类型转换为字符串,null和undefined返回“null”“undefined”
或者直接使用+将一个变量与“”相加,就自动转换了。
Object
ECMAScript中的对象其实就是一组数据和功能的集合。通过new操作符后跟要创建的对象类型名来创建。
var o = new Object();
在ECMAScript中所有的其它实例的基础就是Object类型,所以Object类型所具有的所有属性和方法也存在于更具体的对象中。Object的每个实例都有下列属性和方法:
- constructor:用于创建当前对象的函数,相当于Java里的构造函数
- hasOwnProperty(propertyName):检查给定属性是否存在于当前对象实例中,propertyName要用字符串形式
- isPrototypeOf(object):检查调用对象是否是传入对象的原型
- propertyIsEnumerable(propertyName):检查传入的属性是否可以用for-in枚举
- toLocaleString():返回对象的字符串表示,且根据执行的地区进行本地化
- toString():返回对象的字符串表示
- valueOf():返回对象的字符串,布尔值或数值表示,通常与toString()方法相同
Object是ECMAScript中其他对象的基础,但是JavaScript中的对象不一定继承自Object,比如DOM,BOM对象,这些对象都属于宿主对象,由宿主定义并提供实现。
操作符
在ECMAScript中,操作符可以用于多种数据类型,你可以将一个Number和一个String加起来
一元操作符
递加和递减
++和–在JS中和其它的语言中没啥区别,不过特点就是可以应用于字符串、布尔值,浮点数值和对象。会把它们先转化成数字,在进行加减操作。
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.1000000000000000009(浮点数计算的通病)
o--; //-2
一元加减
位操作符
按位非~
按位与&
按位或|
按位异或^
左移<<
右移有符号>>
右移无符号>>>
布尔操作符
逻辑非!
可以应用于任何值,对于任何值,这个操作符都会返回布尔值。
连续使用两个逻辑非与使用Boolean()函数效果相同。
alert(!false); // true
alert(!"blue"); // false
alert(!0); // true
alert(!NaN); // true
alert(!""); // true
alert(!12345); // false
逻辑与&&
同样可以应用于任何值,但是要注意的是,在有一个操作数不是布尔值的情况下,逻辑与就不一定返回布尔值。
- 如果第一个操作数是对象,则返回第二个操作数
- 如果第二个操作数是对象,则只在第一个操作数求值结果为true时才返回该对象
- 如果两个操作数都是对象,则返回第二个操作数
- 如果有一个操作数是Null,NaN,undefined,则直接返回他们
如果第一个操作数是false,就意味着结果已经决定了,就不会对第二个操作数求值了,就算第二个操作数那里有未定义的变量之类的错误也不会报错,但如果第一个操作数是True,那这个错误就会暴露出来。
逻辑或
这里与逻辑与类比
- 如果第一个操作数是对象,则返回第一个操作数
- 如果第二个操作数是对象,则只在第一个操作数求值结果为false时才返回该对象
- 如果两个操作数都是对象,则返回第一个操作数
- 如果两个操作数是Null,NaN,undefined,则直接返回他们。
逻辑或的特性被用来避免变量被赋空值
var myObject = preferredObject || backupObject;
乘性操作符
乘法、除法、求模这三个乘性操作符。如果参与乘性计算的某个操作数不是数值,那么ECMAScript会先调用Number()将其转换为数值。
乘
- Infinity与0相乘结果是NaN
除
- Infinity被Infinity除结果NaN
- 0被0除结果NaN
- 非0有限数被0除结果正负Infinity
- Infinity被任何数除(包括0)结果正负Infinity
求模
- 无穷大%有限大=NaN
- 有限大%零=NaN
- Infinity%Infinity=NaN
- 有限大%无限大=有限大的值
- 0%任何数=0
加性操作符
加法
Infinity加-Infinity=NaN
如果有一个是字符串,则另一个操作数也转换为字符串,拼接
这一点要尤其注意:
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
alert(message); // "The sum of 5 and 10 is 510"
message = "The sum of 5 and 10 is " + (num1 + num2);
alert(message); //"The sum of 5 and 10 is 15"
减法
减法并没有字符串操作,其他操作的规则同加法类比。
关系操作符
大于,小于,小于等于,大于等于。他们接收两个操作数,返回一个布尔值。
- 比较两个字符串时,就是比较两个字符串对应字符的编码值
- 如果一个操作数是数值,那么另一个操作数就会被转换为一个数值,然后进行比较
- 如果一个操作数是对象,则调用valueOf(),如果还没有就调用toString()方法。
- 任何数与NaN进行比较结果都是false。
相等操作符
相等和不相等==、!=
这两个操作符都会先强制转换操作数,然后再比较他们的相等性
- 布尔值会被转换为0、1
- 如果一个操作数是字符串,一个是数值,在比较相等性之前,字符串会被转换为数值
- 一个操作数是对象,另一个不是,则调用对象的valueOf()方法转换
- null与undefined是相等的。这两个与其他的进行比较时不会被转换
- NaN与任何操作数不等,包括他自己。
- 两个操作数都是对象时,则比较他们是不是同一个对象
全等和不全等===
这个操作符不强制转换操作数,相等就是相等,不等就是不等。
var result1 = ("55" == 55); //true
var result2 = ("55" === 55); //false
var result3 = (null === undefined); //false
条件操作符
根据boolean_expression表达式的值决定给变量赋哪个值。
variable = boolean_expression ? true_value : false_value;
赋值操作符
就是等于号啦。+=、%=什么的可以复合使用
逗号操作符
var num1=1, num2=2, num3=3;
逗号操作符用于赋值时,总会返回表达式最后一项
var num = (5, 1, 4, 8, 0); // num的值为 0
语句
for
这里有个问题要注意,ECMAScript中不存在块级作用域,因此循环内部的变量也可以在外部访问到。
var count = 10;
for (var i = 0; i < count; i++){
alert(i);
}
alert(i); //10
for语句中的初始化表达式,控制表达式,循环后表达式都是可选的,这三个表达式全部省略就会创建一个无限循环,只给出控制表达式其实就是一个while循环。
for (;;) { //无限
doSomething();
}
var count = 10;
var i = 0;
for (; i < count; ){
alert(i);
i++;
}
for-in语句
原来JS里也有for-in语句~用来枚举对象的属性。不要用来迭代数组
for (var propName in window) {
document.write(propName);
}
break
立即退出循环并执行循环后面的语句。
continue
退出本次循环,执行下次循环。
label
用来给代码添加标签,通常是为了给break和continue的跳跃提供目标。
var num = 0;
outermost:
for (var i=0; i < 10; i++) {
for (var j=0; j < 10; j++) {
if (i == 5 && j == 5) {
break outermost;
}
num++;
}
}
alert(num); //55
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;
}
在with语句中,每个变量被认为是一个局部变量,在局部环境中找不到该变量的定义时就会查询指定对象中是否有同名属性,如果有就将属性的值作为变量的值。
不过with会带来性能和调试问题,不建议使用。
switch
如果不需要混合case,务必在每个case执行的语句最后加上break,如果要混合请注释写明。
case后面可以跟表达式,switch语句在比较值的时候使用的是全等操作符,故比较时不会发生类型转换。
函数
参数
在ECMAScript中,传递多少个参数并不受函数定义的限制,即便你的函数定义时声明接收两个参数,你还是可以传0至任意个参数。参数在ECMAScript中是用数组表示的,函数接收到的也是这个数组,在函数体内可以通过arguments对象来访问到这个数组,arguments虽然并不是一个数组的实例,但是可以通过下标来访问每一个元素,也可以通过length来确定参数的个数。以下两个函数在调用时并没有区别。
function sayHi(name, message) {
alert("Hello " + name + "," + message);
}
function sayHi() {
alert("Hello " + arguments[0] + "," + arguments[1]);
}
这也说明了在调用函数时解析器并不会检查参数的命名,个数之类的事情。
且在函数体内,修改arguments里的值或命名参数的值都会同时修改与之对应的另一方,也就是说这两个值是绑定的,不过并不是说它们共享内存空间,只不过是简单的绑定在一起而已。
function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
doAdd(1,1); //11
如果你传递的参数不够,那么没被传递的命名参数将是undefined。
arguments的长度是由调用时实际传递的参数决定的。
在严格模式下,arguments不能赋值。
参数传递永远都是值传递,木有引用这一说。
没有重载
ECMAScript中没有函数签名,所以重载也做不到。同名函数的话,先定义的会被后定义的覆盖掉,不过通过检查arguments的个数可以模仿一下重载。