JavaScript高级程序设计笔记(1)

script type

向HTML页面插入Javascript标签,主要通过 script 标签。script标签中的type属性, 用来表示编写代码使用的脚本语言的内容类型(MIME)。 text/script 和 text/ecmascript 都已经不推荐使用, 但我们一般还是用 text/script。
实际上,服务器在传送 Javascript 时,使用的MIME类型通常是 application/x-javascript。 但在 type 中设置这个值可能导致脚本被忽略。 在非IE浏览器下还可以使用 application/javascript 和 application/ecmascript。 从约定俗称和浏览器兼容性考虑, 目前 type 属性值还是text/javascript。该属性非必须,如果没有指定,默认为 text/javascript。

javascript 数据类型

ECMAScript中有5中简单数据类型: Undefined、Null、 Boolean、 Number 和 String。还包括一种复杂数据类型: Object。

typeof 操作符

用来检测变量的数据类型,返回值为: undefined、 boolean、 number、 string、 object、 function。

  • 关于 null,从逻辑角度讲, null值表示一个空指针,所有 typeof null 会返回 ‘object’。
  • 实际上 undefined 值是派生自 null值。因此 ECMAScript 规定 null == undefined 为 true.

关于浮点数计算问题

所谓浮点数值,就是数值中必须包含小数点,且小数点后必须至少有一位数字。 但是浮点数的计算精度远低于整数,因此不推荐在js中做大量的浮点数运算。

1
2
3
console.log(0.1+0.2);//0.30000000000000004
console.log((1-0.9)==0.1);//false
console.log(1-0.9);0.09999999999999998

关于浮点数计算精度问题,是所有使用基于IEEE754数值的浮点计算问题,并非ECMAScript一家。一般浮点计算,先转换成整数运算再去换算。

来看一道关于number的笔试题:

1
2
3
4
5
var two   = 0.2
var one = 0.1
var eight = 0.8
var six = 0.6
[two - one == one, eight - six == two]

答案是:[true, false].

1
2
3
if(a + b == 0.3){
console.log("You've got 0.3");
}

在这个例子中我们测试,两个数的和是否等于0.3:如果连个数是0.05和0.25,那么测试可以通过;如果是0.1和0.2就不能通过,因此永远不要测试某个特定的浮点数值。

还是关于Number

首先来看一个问题:

1
2
console.log(parseInt(070));
console.log(paresInt('070'));

上面最后的输出是什么呢?第一条命令输出的是 56, 第二条命令输出的是 70(基于Chrome浏览器的输出)。同一条命令在Ecscript3和5上解析的是有问题的, 第二条命令,Ecsript3会把‘070’解析成八进制字面量,解析成56,而Ecscript5则会解析成 70。为了使用者消除困惑,parseInt函数允许接收第二个参数,按照指定进制解析字符串。

1
2
3
console.log(parseInt('070',10));//70
console.log(parseInt('070',8));//56
console.log(parseInt(070,8));//46,这个是因为070,转换成十进制后是56,8进制的56换算成十进制是46

在这里讲一下,parseInt方法:

1、定义和用法
parseInt() 函数可解析一个字符串,并返回一个整数。
2、语法
parseInt(string, radix)
其中,string 必需,要被解析的字符串;radix 可选,表示要解析的数字的基数。该值介于 2 ~ 36 之间。
如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。
如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。

3、返回值:返回解析后的数字。
4、tips:当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。
举例,如果 string 以 “0x” 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt()的一个实现把其后的字符解析为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。

再来一道笔试题:

1
["1", "2", "3"].map(parseInt)

知识点:
1、Array/map
2、Number/parseInt
3、JavaScript parseInt
首先, map接受两个参数, 一个回调函数 callback, 一个回调函数的this值

1
array.map(callback,[ thisObject]);

其中的callback相当于:

1
2
3
[].map(function(value, index, array) {
// ...
});

callback接收三个参数:value, index, array. 在本题目中, map只传入了回调函数–parseInt.
其次, parseInt 只接受两个两个参数 string, radix(基数),关于parseInt的介绍,参照上文。
所以本题相当于

1
2
3
4
//第一个参数为array[index],第二个参数为 index。
parseInt('1', 0);
parseInt('2', 1);//radix值,介于2到36之间。该参数不合法,返回NaN
parseInt('3', 2);//二进制数值0/1,string参数不合法,返回NaN

后两者参数不合法,所以答案是 [1, NaN, NaN]

Object

重点来了,Object类型。在ECMAScript中,对象其实是一组数据和功能的集合。对象可通过执行new操作符后跟要创建的对象类型的名称来创建。创建Object类型的实例,并为其添加属性和(或)方法,就可以创建自定义对象。
关于对象,要理解一个重要思想:

在ECMAScript中,Object类型是它所有实例的基础。即Object类型所具有的任何属性和方法,同样存在于更具体的对象中。

Object每个实例都具有以下属性和方法:

  • Constructor: 保存着用于创建当前对象的函数。
  • hasOwnProperty(propertyname): 用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中作为属性名(propertyname)必须以字符串形式指定。
  • isProperyOf(object): 用于检查传入的对象是否是另一个对象的原型。
  • propertyIsEnumberable(propertyname): 用于检查给定的属性能否用for-in来枚举。参数名必须以字符串形式指定。
  • toLocaleString(): 返回对象的字符串表示,该字符串于执行环境的地区相对应。
  • toString(): 返回对象的字符串表示。
  • valueOf(): 返回对象的字符串、数字或布尔值表示。通常与toString()方法返回值相同。

由于在ECMAScript中,Object是所有对象的基础,因此所有对象都具有这些属性和方法。

逗号操作符

逗号操作符多用于声明多个变量,除此之外逗号操作符还可以用于赋值。在用于赋值时,逗号操作符总会返回表达式中的最后一项。

1
2
var num1 = 1, num2 = 2, num3 = 3;
var num = (1, 2, 3, 4, 5);//num值为5

语句

  • if语句
  • do-while语句
    后测试循环语句,只有在循环体中的代码执行之后,才会对条件表达式求值。(即循环体内的代码至少执行一次后才进行判断。)
1
2
3
4
5
var i =;
do{
i += 2;
} while(i < 10);
console.log(i);//10
  • while语句
    与do-while相反,属于先测试语句,在循环体代码执行之前,先对表达式求值,循环体内的代码有可能永远不会被执行。
1
2
3
4
5
var i = 0;
while (i < 10){
i += 2;
}
console.log(i);//10
  • for语句
    前测试循环语句,具有执行循环之前初始化变量和定义循环后要执行代码的能力。

  • for-in语句
    精准迭代语句,用于枚举对象属性。但是循环输出的对象属性名顺序是不可预测的。

  • label语句

  • break和continue语句
    break:立即退出循环,强制继续执行循环后面的语句。
    continue:立即退出循环,从循环顶部继续执行。

break demo:

1
2
3
4
5
6
7
8
var num = 0;
for(var i = 1; i < 10; i++){
if(i % 5 == 0){
break;
}
num++;
}
console.log(num);//4

continue demo:

1
2
3
4
5
6
7
8
var num = 0;
for(var i = 1; i < 10; i++){
if(i % 5 == 0){
continue;
}
num++;
}
console.log(num);//8
  • with语句
    将代码的作用于设定到一个特定的对象中。
    with(expression) statement;

demo:

1
2
3
4
5
6
7
8
9
var qs = location.search.sbustring(1);
var hostname = location.hostname;
var url = location.href;

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

上述代码块中,使用with语句关联了location对象,在with语句代码块内部,每个变量首先被认为是一个局部变量,如果局部环境中找不到该变量定义,就会查询location对象中是否有同名属性,如果发现同名属性,则以location对象属性值作为变量的值。

严格模式下,不允许使用with语句,否则将视为语法错误!

  • switch语句
    流控制语句
1
2
3
4
5
6
7
8
9
10
switch(expression){
case value: statement
break;
case value: statement
break;
case value: statement
break;
...
default: statement
}