JavaScript高级程序设计(第2版)

3.4 数据类型

  ECMAScript有5种简单的数据类型,也称为基本数据类型,Undefined、Null、Boolean、Number和String,还有一种复杂数据类型——Object。

3.4.1 typeof操作符

  typeof用来检测给定变量的数据类型,对一个值使用typeof操作符可能返回下列某个字符串:

  “undefined”——如果这个值未定义

  “boolean”——如果这个值是布尔值

  “string”——如果这个值是字符串

  “number”——如果这个值是数值

  “object”——如果这个值是对象或null;

  “function”——如果这个值是函数l;

3.4.2 Undefined类型

  Undefined类型只有一个值,即特殊的undefined。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。

  例如:

1 var message; 
2 alert(typeof message); //undefined
3 alert(message == undefined); //true

  另外,对未定义的变量使用typeof,返回值也是undefined

  例如: 1 alert(typeof ff); //undefined 

3.4.3 Null类型

  Null类型也只有一个值,即null,null值表示一个空对象指针,而这也是使用typeof操作符检测null值时会返回"object"的原因,例如:

  var car = null;
  alert(typeof car); //object

  如果定义的变量准备在将来用于保存对象,那么最好将变量初始化为null,而不是其他值。这样,只要直接检查null值就可以知道相应的变量是否已经保存了一个对象的引用了。

if(car != null){
  //对car对象执行某些操作  
}

3.4.4 Boolean类型

  Boolean类型有2个字面值:true和false。

  对于任何数据类型调用Boolean()函数,总会返回一个Boolean值。例如:

var message = "some string";
var messageAsBoolean = Boolean(message);

  至于返回的值是true还是false,取决于要转换值的数据类型以及实际值,下面给出了各种数据类型及其对应的转换规则:

数据类型 转换为true的值 转换为false的值
Boolean true false
String 任何非空字符串 ”“(空字符串)
Number 任何非零数字值(包括无穷大) 0和NaN
Object 任何对象 null
Undefined n/a(not application 不适用) undefined

var
message = "some string"; if(message){ alert("Value is true"); }

3.4.5 Number类型

var intNum = 55; //十进制55
var octalNum = 070; //八进制56
var octalNum = 079; //无效的八进制,解析为79(字面值中的数值超出了范围,前导零将被忽略)
var hexNum1 = 0xA; //十进制10

1. 浮点数值

  由于保存浮点数值需要的内存空间是保存整数值的2倍,因此ECMAScript会不失时机地将数值转换为整数值。例如:

var floatNum = 1.; //小数点后面没有数字,解析为1
var floatNum = 10.0; //浮点数值本身表示的就是一个整数,改值会被转换成整数,解析为10

  e表示法,即科学计数法

var floatNum = 3.125e7; //31250000
var floatNum = 3e-7; //0.0000003

  永远不要测试某个特定的浮点数值,例如:

var a = 0.05;
var b = 0.25;
if(a + b == 0.3){ //永远不要做这样的测试 
    alert("true");
}else{
    alert("false");
} //输出结果是false

2. 数值范围

  由于内存的限制,ECMAScript并不能保存世界上所有的数值,ECMAScript能够表示的最小数值保存在Number.MIN_VALUE中,在大多数浏览器中,这个值是5e-324,能够表示的最大数值保存在Number.MAX_VALUE中,在大多数浏览器中,这个值是1.7976931348623157e+308。如果某次计算的结果的得到了一个超出JavaScript数值范围的值,如果这个值是负数,则会被转换为-Infinity(负无穷),如果这个数值是整数,则会被转换为Infinity(正无穷)。isFinite()函数可以检测一个数值是不是有穷的。

3. NaN

  NaN(Not a Number)isNaN()函数接受一个参数,函数确定这个参数是否”不是数值“

alert(isNaN(NaN)); //true
alert(isNaN(10)); //false, 10是一个数值
alert(isNaN("10")); //false, "10"可以被转换成数值10
alert(isNaN("blue")); //true, 不能转换成数值
alert(isNaN(true));  //false, 可以被转换成数值1

4. 数值转换

  有3个函数可以把非数值转换成数值:Number()、parseInt()和parseFloat()。Number()可以用于将任何数据类型转换成数值,而parseInt()和parseFloat()函数专门用于将字符串转换成数值。

Number():

  如果是Boolean值,true和false将分别被转换成1和0。例如: var number = Number(true); //1 

  如果是数字值,只是简单的传入和返回。

  如果是null值,返回0。 var number = Number(null); //0 

  如果是undefined,返回NaN。 var message; var number = Number(message); //NaN 

  如果是字符串,遵循下列规则:

    如果字符串中只包含数字,则将其转换为十进制数值,即”1“会变成1,”123“会变成123,而”011“会变成11(前导的零被忽略了)

    如果字符串中包含有效地浮点格式,如”1.1“,则将其转换成对应的浮点数值。

    如果字符串中包含有效的十六进制格式,如”0xf“,则将其转换为相同大小的十进制整数。 var number = Number("0xf"); //15 

    如果字符串是空的,即不包含任何字符,则将其转换为0。 var number = Number(""); //0 

    如果字符串中包含以上格式之外的字符,则将其转换为NaN。 var number = Number("Hell0 112"); //NaN 

  如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值,如果转换的结果是NaN,则调用对象的toString()方法,然后再次依照前面的规则转换返回的字符串值。

parseInt():

  parseInt()会忽略字符串前面的空格,直至找到第一个非空格字符,如果第一个字符不是数字字符或者负号,则parseInt()就会返回NaN。也就是说,

var number = parseInt(""); //NaN
var number = Number(""); //0

  如果第一个字符是数字字符,parseInt()会继续解析第二个字符,知道解析完所有后续字符或者遇到了一个非数字字符。例如:

var number = parseInt("1234blue"); //1234,因为"blue"会被完全忽略
var number = parseInt("22.5"); //22, 因为小数点并不是有效的数字字符

  parseInt()也能够识别出八进制、十进制、十六进制。例如:

var number = parseInt("070"); //56, 八进制
var number = parseInt("70");   //70, 十进制
var number = parseInt("0xf"); //15, 十六进制

  还有一种方式,指明基数16作为第二个参数,例如:

var number = parseInt("0xAF",16); //175
var number = parseInt("AF",16);  //如果指定了16作为第二个参数,字符串可以不带前面的"0x"
var number = parseInt("AF"); //NaN

  指定基数会影响转换的输出结果:

var number = parseInt("010",2); //2,按二进制解析
var number = parseInt("010",8); //8,按八进制解析
var number = parseInt("010",10); //10,按十进制解析
var number = parseInt("010",16); //16,按十六进制解析

  由于不指定基数则意味着让parseInt()决定如何解析输入的字符串,因此为了避免错误的解析,建议无论在什么情况下都明确指定基数,特别像下面这样处理八进制的情况下:

var number = parseInt("010"); //8,按八进制解析
var number = parseInt("010",8); //8,按八进制解析
var number = parseInt("010",10); //10,按十进制解析

parseFloat():

  字符串中的第一个小数点有效,第二个小数点无效。

  另外,parseFloat()始终都会忽略前导的零,parseFloat()始终只解析十进制值,因此它没有用第二个参数指定基数的用法。十六进制字符串始终会被解析为0。

  如果字符串中包含一个可以解析为整数的数,则parseFloat()会返回整数。

var number = parseFloat("1234blue"); //1234
var number = parseFloat("0xA"); //0
var number = parseFloat("22.5"); //22.5
var number = parseFloat("22.35.5");  //22.35
var number = parseFloat("0908.5");  //908.5
var number = parseFloat("3.125e7"); //31250000

3.4.6 String类型

  1. ECMAScript中的字符串是不可变的。也就是说,字符串一旦创建,它们的值就不能改变,要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。

var lang = "Java";
lang = lang + "Script";

  以上示例中的变量lang开始时包含字符串”Java"。而第二行代码把lang的值重新定义为“Java”和“Script”的组合,即“JavaScript”。实现这个组合的过程如下:

  首先创建一个能容纳10个字符的新字符串,然后在这个字符串中填充“Java”和“Script”。最后一步是销毁原来的字符串“Java”和“Script”,因为这两个字符串已经没用了。

  2. 转换成字符串

  toString(),数值、布尔值、对象和字符串值都有toString()方法,但是null和undefined值没有这个方法。例如:

var age = 11;
var ageAsString = age.toString();
var found = true;
var foundAsString = found.toString();

  带有参数的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(),如果值有toString()方法,则调用该方法并返回相应的结果;如果值是null,则返回“null”;如果值是undefined,则返回“undefined”。

var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1));  //10
alert(String(value2));  //true
alert(String(value3));  //null, null和undefined没有toString()方法,String()函数就返回了这两个值的字面值。
alert(String(value4));  //undefined

 3.5 操作符

  1. 一元加和减操作符

  一元加操作符以一个加号(+)表示,放在数值前面,对数值不会产生任何影响。例如:

var num = 25;
num = +num; //仍然是25

  不过,在对非数值应用一元加操作符时,该操作符会像Number()转型函数一样对这个值执行转换。话句话说,布尔值true和false将被转换成1和0,字符串会被按照一组特殊的规则进行解析,对对象是先调用它们的valueOf()和toString()方法,再转换得到的值。例如:

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
    valueOf: function(){
        return -1;
    }
};
        
s1 = +s1; //值变成数值1
s2 = +s2; //值变成数值1.1 
s3 = +s3;
//值变成NaN
b = +b;
//值变成数值0
f = +f;
//值未变,仍然是1.1
o = +o;
//值变成数值-1

  一元减操作符主要用于表示负数,例如将1转换成-1,举个例子:

var num = 25;
num = -num;  //-25

  在将一元减操作符应用于数值时,该值会变成负数,而应用于非数值时,一元减操作符遵循与一元加操作符相同的规则,最后再将得到的数值转换成负数,例如:

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
    valueOf: function(){
         return -1;
    }
};
        
s1 = -s1; //值变成数值-1
s2 = -s2; //值变成数值-1.1 
s3 = -s3; //值变成NaN 
b = -b; //值变成数值0 
f = -f; //值未变,仍然是-1.1 
o = -o; //值变成数值1

3.5.2 位操作符

  1. 按位非(NOT)

  执行按位非的结果就是返回数值的反码,按位非操作的本质:操作数的负值减1。例如:

var num = 25;
num = ~num; //-26
var num2 = -25;
num2 = ~num2;//24

  2. 左移

  左移由<<表示,这个操作符会将数值的所位(是所有的位,包括符号位,即最高位也要向左移动)向左移动指定的位数,例如:

var oldValue = -2;  //相当于二进制的10
var newValue = oldValue << 5; //相当于二进制的1000000,十进制的64
alert(newValue );  //64

  像左移动后,原数值的右侧多出了5个空位,左移操作会以0来填充这些空位,以便得到的结果是一个完整的32位二进制数。

0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0

第一行的32位数表示数值2130706687,左移5位(包括符号位)之后变成了-536862752,也就是左移由正数变成了负数。

  3. 有符号的右移

  有符号的右移操作符由>>表示,这个操作会将数值向右移动指定的位数,但保留符号位。例如:

var oldValue = 64; //等于二进制的1000000
var newValue = oldValue >> 5;//等于二进制的10,即十进制的2
alert(newValue);// 2

  在移位的过程中,原数值也会出现空位,只不过这次的空位出现在原数值的左侧,符号位的右侧,而此时ECMAScript会用符号位的值来填充所有空位,以便得到一个完整的值。

数值64:

0(符号位) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0

数值64向右移动5位(得到2)(符号位后面的5位是根据符号位填充的)

0(符号位) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0

  3. 无符号的右移

  无符号的右移操作符由>>>表示,这个操作数会将数值的所有32位都向右移动,包括最高位也要向右移动,右边空出的位用0填充。对正数的无符号右移和有符号的右移结果相同,但是负数的结果就不一样了,无符号右移后的结果会非常之大。例如:

  

var oldValue = -64; //等于二进制的11111111111111111111111111000000
var newValue = oldValue >>> 5; //等于二进制的134217726

数值-64: 

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0

数值-64无符号向右移动5位之后:

0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0

3.5.5 加性操作符

  1. 加法

  字符串和数字的加法:将数字转换成字符串,然后再将两个字符串拼接起来。例如:

1 var result1 = 5 + 5;  //10
2 var result2 = 5 + "5";  //55
3 
4 var number1 = 5;
5 var number2 = 10;
6 var message1 = "The sum of 5 and 10 is " + number1 + number2; //The sum of 5 and 10 is 510
7 var message2 = "The sum of 5 and 10 is " + (number1 + number2); //The sum of 5 and 10 is 15

  第6行的结果是这样产生的:每个加法操作都是独立执行的,第一个加法操作将一个字符串和一个数值(5)拼接起来,结果是一个字符串(

The sum of 5 and 10 is 5),而第二个加法操作又用这个字符串去加另一个数值(10),当然也会得到一个字符串(
The sum of 5 and 10 is 510。)。
 第7行是先计算小括号内的加法,再将前面的字符串和加法的结果拼接起来。

  2. 减法

  如果有一个操作数是字符串、布尔值、null、undefined,则先在后台调用Number()函数将其转换为数值,然后再进行减法操作,如果转换的结果是NaN, 则减法的结果就是NaN。例如:

var result1 = NaN - 1;//NaN, 如果有一个操作数是NaN,则结果是NaN
var result2 = 5 - true; //4, 先将true转换成1
var result3 = 5 - 3;
var result4 = 5 - "";  //5, 先将“”转换成0
var result5 = 5 - "2"; //3, 先将字符串“2”转换成数值2
var result6 = 5 - null; //5, null被转换成数值0

3.5.6 关系操作符

  <、 >、 <=、 >=

  如果两个操作数都是数值,则执行数值比较。例如: var result = 23 > 3; //true 

  如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。例如: 

var result = "Black" < "apple"; //true,字母B的字符编码是66,字母a的字符编码是97
var result = "23" > "3"; //false, 两个操作数都是字符串,字符串比较的是字符编码,”2“的字符编码是50,”3”的字符编码是51

  如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值的比较。例如: var result = "23" > 3; //true, 字符串”23“被转换为数值23,再比较23和3 

  如果一个操作数是对象,则valueOf()--->toString()

  如果一个操作数是NaN,则结果是false。

var result = NaN > 3;
var result = NaN <= 3; //任何操作数与NaN进行关系比较,结果都是NaN

 3.5.7 相等操作符

  1. 相等(==)和不相等(!=)-----先转换再比较

  如果有一个操作数是布尔值,在比较相等性之前先将其转换为数值------false转换为0,true转换为1。 var result = (true == 1); //true 

  如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值。 var result = ("5" == 5); //true 

  如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的原始值按照前面的规则进行比较。

  null和undefined是相等的。 var result = (null == undefined); //true 

  在比较相等性之前,不能将null和undefined转换成其他任何值。

var result = (null == 0); //false
var result = (undefined == 0); //false

  如果有一个操作数是NaN, 则相等操作符的返回结果是false。

var result = ("NaN" == NaN); //false
var result = (NaN == NaN);    //false
var result = (5 == NaN);        //false
var result = (NaN != NaN);    //true

  2. 全等(===)和不全等(!==) ------仅比较而不转换

  全等(===)仅在两个操作数未经转换就相等的情况下返回true。例如: var result = (5 === 5); //true 

var result1 = ("55" == 55);  //true,因为转换后相等
var result2 = ("55" === 55); //false, 因为不同的数据类型不相等

3.7 函数

  可以通过arguments.length获取函数传递参数的个数。例如:

function sayHi(){
    alert(arguments.length);
}
sayHi("name1","name2","name3","name4"); //4
sayHi(); //0
sayHi("name1"); //1

  可以通过arguments[0]、arguments[1]等获取参数。例如:

function sayHi(){
    alert(arguments.length);  //4
    alert(arguments[0] + ":" + arguments[1] + ":" + arguments[2]); //name1:name2:name3
}
sayHi("name1","name2","name3","name4");

  ECMAScript函数没有传统意义上的函数重载,如果定义两个名字相同的函数,则后面的函数会覆盖前面定义的函数。例如:

function sayHi(num){
    return num + 100;
}
function sayHi(num){
    return num + 200;
}
var result = sayHi(100);
alert(result);  //300,后面定义的sayHi()函数覆盖了前面定义的sayHi()函数

4.1 基本类型和引用类型的值

  基本类型值:那些板寸在栈内存中的简单数据段,即这些之完全保存在内存中的一个位置,并且每个值分别占据着固定大小的空间,可以按顺序来访问它们。

  5种基本数据类型:Undefined、Null、Boolean、Number、String(这5种基本数据类型的变量都保存在栈内存中)

  引用类型值:那些保存在堆内存中的对象,即变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。

  4.1.1 对于引用类型的值,可以为其添加属性和方法,也可以改变和删除其属性和方法。例如:

var person = new Object();
person.name = "name1";
alert(person.name);  //name1

  但是,不能给基本类型的值添加属性,尽管这样做不会导致任何错误。例如:

var name = "name1";
name.age = 27;
alert(name);  //name1
alert(name.age); //undefined

  4.1.2 从一个变量向另一个变量复制基本类型的值,会在栈中创建一个新值,然后把该值复制到为新变量分配的位置上。例如:

var number1 = 5;
var number2 = number1;
alert(number2); //5

  上面例子中,number1和number2的值都是5,但是number1和number2在栈内存中完全独立的,这两个变量可以参与任何操作而不会相互影响。

  复制前的栈空间                  

   
   
number1

5

(Number类型)

  复制后的栈空间

   
number2

5

(Number类型)

number1

5

(Number类型)

   从一个变量向另一个变量复制引用类型的值时,同样也会将存储在栈中的值复制一份放到为新变量分配的空间中,不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量。例如:

var obj1 = new Object();
obj1.name = "ob1-name";
var obj2 = obj1;
obj2.name = "obj2-name";
alert(obj1.name); //obj2-name

 4.2.2 没有块级作用域

  例如:

if(true){
    var color = "blue";
}
alert(color);  //blue

  如果是在C、C++或Java中,color会在if语句执行完毕后被销毁。但在JavaScript中,上述if语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境)中。

  1. 声明变量

  在使用var关键字声明变量时,这个变量将被自动添加到距离最近的可用环境中。如果变量在未经声明的情况下被初始化,那么该变量会被自动添加到全局环境中。例如:

function add(num1,num2){
    var sum = num1 + num2;
        return sum;
}
var result = add(10,20);
alert(sum);//由于sum不是有效的变量,因此会导致错误  

但是:
function add(num1,num2){
    sum = num1 + num2;
        return sum;
}
var result = add(10,20);
alert(sum);//由于sum在初始化时并没有使用var关键字,于是,在调用add()之后,添加到全局环境中的变量sum将继续存在,即使函数已经执行完毕,后面的代码依旧可以访问它。

4.3 垃圾收集

  IE中有一部分对象并不是原生的JavaScript对象,例如,其BOM和DOM中的对象就是使用C++以COM(Component Object Model, 组件对象模型)对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数策略(引用计数策略的缺陷是循环引用,即循环引用的对象不再使用时也不能得到回收)。因此,即使IE的JavaScript引擎是使用标记清除策略来实现的,但JavaScript访问的COM对象依然是基于引用计数策略的。换句话说,只要IE中涉及COM对象就会存在循环引用的问题。例如:

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

  这个例子在一个DOM元素(element)与一个原生的JavaScript对象(myObject)之间创建了循环引用。其中,变量myObject有一个名为element的属性指向element对象,而变量element也有一个属性名叫someObject回指myObject。由于存在这个循环引用,即使例子中的DOM从页面中移除,它也永远不会被回收。

  为了避免类似这样的循环引用问题,最好是在不使用它们的时候手工断开原生JavaScript对象与DOM元素之间的链接。例如:

myObject.element = null;
element.someObject = null;

 4.3.3 性能问题。

  IE6及其IE更低版本的垃圾收集器是根据内存分配量运行的,具体一点说就是256个变量、4096个对象(或数组)字面量或者数组元素(slot)或者64KB的字符串。达到上述任何一个临界值,来及收集器就会运行。这种实现方式的问题在于,如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量。而这样一来,垃圾收集器就不得不频繁地运行。结果,由此引发的严重性问题促使IE7重写了垃圾收集例程。

  IE7的JavaScript引擎的垃圾收集例程改变了工作方式:触发垃圾收集的变量分配、字面量和(或)数组元素的临界值被调整为动态修正。IE7中的各项临界值在初始时与IE6相等。如果垃圾收集例程回收的内存分配量低于15%,则变量、字面量和(或)数组元素的临界值就会加倍,如果例程回收了85%的内存分配量,则将各种临界值重置回默认值。

5. 引用类型

  5.2 Array类型

  ECMAScript数组的每一项可以保存任何类型的数据。也就是会所,可以用数组的第一个位置保存字符串,用第二个位置来保存数值,第三个位置保存对象。并且,ECMAScript数组的大小时可以动态调整的,可以随着数据的添加自动增长以容纳新增数据。

  创建数组的两种方式:(1)使用Array构造函数 (2)使用数组字面量表示法

  (1)使用Array构造函数

var colors = new Array();  //使用Array构造函数创建数组
var colors = new Array(20); //如果预先知道数组要保存的项目数量,也可以给构造函数传递该数量
var colors = new Array("red","blue","green");//向构造函数传递数组中应该包含的项,创建一个包含3个字符串的数组
//给构造函数传递一个值可以创建数组,但是如果传递的是数组,则会按照该数值创建包含给定项数的数组,而如果传递的是其他类型的参数,则会创建包含那个值的只有一项的数组
var colors = new Array(3);  //创建一个包含3项的数组
var colors = new Array("Green"); //创建一个包含1项,即“Green”的数组

  (2)数组字面量表示法

var colors = ["red","blue","green"]; //创建一个包含3个字符串的数组
var colors = []; //创建一个空数组
var colors = [1,2,]; //不要这样!这样在IE中会创建一个包含3项(1,2,undefined)的数组,在其他浏览器中会创建一个包含2项(1,2)的数组
var options = [,,,,,]; //不要这样!这样在IE中会创建一个包含6项的数组,每一项都是undefined。在其他浏览器中会创建一个包含5项的数组,每一项都是undefined。

  在读取和修改数组的值时,要使用方括号并提供相应值的基于0的数字索引,例如:

var colors = ["blue","green","red"];//定义一个字符串数组
alert(colors[0]); //显示第一项
colors[2] = "black"; //修改第三项
alert(colors[2]);
colors[3] = "brown"; //新增第四项
alert(colors[3]);

  数组的length属性不是只读的,通过设置这个属性,可以从数组的末尾移除或者向数组中添加新项、例如:

var colors = ["blue","green","red"];
alert(colors[2]); //red
colors.length = 2; //设置数组colors的length为2,则将数组colors的第3项(“red”)从末尾移除
alert(colors[2]); //undefined
colors[2] = "blown"; //新增一项“blown”,
alert(colors.length); //3
colors.length = 4; //设置数组colors的length为2, 在数组colors的末尾新增一项,值为undefined
alert(colors[3]); //undefined(通过设置colors.lenght新增的项的值都是undefined)

  利用数组的length属性可以方便地在数组末尾添加新项,例如:

var colors = ["blue","green","red"]; //创建一个包含3个字符串的数组
colors[colors.length] = "black"; //(在位置3)添加一种颜色
colors[colors.length] = "blown"; //(在位置4)添加一种颜色

  

var colors = ["blue","green","red"]; //创建一个包含3个字符串的数组
colors[99] = "black"; //(在位置99)添加一种颜色
alert(colors[3]); //undefined
alert(colors.length); //数组的长度是100

   5.2.1 转换方法

  所有对象都有toString()、toLocaleString()和valueOf()方法。

var colors = ["blue","green","red"]; //创建一个包含3个字符串的数组
alert(colors.toString());//返回数组的字符串表示(blue,green,red)。数组中的每一项都调用toString()方法,最后拼接成一个字符串,中间用逗号隔开。
alert(colors.valueOf());//blue,green,red
alert(colors);//alert()要接收字符串参数,所有它会在后台调用toString()方法

  toLocaleString()方法:数组中的每一项都要调用toLocaleString()方法,然后拼接成字符串,中间用逗号隔开。(IE中,逗号后面都会有一个空格,而toString()方法的逗号后面没有空格)

  

var person1 = {
    toLocaleString : function(){
        return "person1_toLocaleString";
    },
    toString : function(){
        return "person1_toString";
    }
};
        
var person2 = {
    toLocaleString : function(){
        return "person2_toLocaleString";
    },
    toString : function(){
        return "person2_toString";
    }
};
        
var person = [person1,person2];
alert(person); //person1_toString,person2_toString
alert(person.toString());//person1_toString,person2_toString
alert(person.toLocaleString());//person1_toString, person2_toString

  数组继承的toLocaleString()、toString()和valueOf()方法,在默认情况下都会以逗号分隔字符串的形式返回数组项。而如果使用join()方法,则可以使用不同的方法来构建这个字符串。join()方法重现了toString()方法的输出。例如:

var colors = ["blue","green","red"];
alert(colors.join(""));//blue、green、red
alert(colors.join("|"));//blue|green|red

  5.2.2 栈方法

  push()方法返回的是数组的length,pop()方法返回的是数组的最后一项,也就是删除的那一项。例如:

var colors = new Array();
var count = colors.push("red","green");
alert(count); //2, push()方法返回的是数组的length
        
count = colors.push("black");
alert(count);
        
var item = colors.pop();
alert(item); //black, pop()方法返回的是数组的最后一项,也就是删除的那一项
alert(colors.length); //2

  5.2.3 队列方法

  数组的队列方法是先进先出,shift()方法从数组的前端取得数据。而pop()是从数组的最后端取得数据。

var colors = new Array();
var count = colors.push("red","green");
alert(count); //2, push()方法返回的是数组的length
        
count = colors.push("black");
alert(count);
        
var item = colors.shift();
alert(item); //red, shift()方法返回的是数组的第一项,也就是从前端移除的项
item = colors.pop();
alert(item); //black, pop()方法返回的是数组的最后一项,也就是删除的那一项
alert(colors.length); //10

  unshift()方法是在数组的最前端推入一项。例如:

var colors = new Array();
var count = colors.push("red","green");
alert(count); //2
count = colors.unshift("black","brown"); //unshift()方法是在数组的前端添加任意个项并返回数组的长度,但是在IE中返回值count竟然是undefined
alert(count); //在IE中是undefined,在chrome中是4
alert(colors.toString()); //black、brown、red、green
alert(colors.length); //4

  5.2.4 重排序方法

  reverse()方法,反转数组项的顺序

var values = [1,2,3,4,5];
values.reverse();
alert(values); //5,4,3,2,1

  sort()按升序排列数组项,数组中的每一项都要用toString()方法转型成字符串再进行比较,即使数组中的每一项都是数组,sort()方法比较的也是字符串。

var values = [0,1,5,10,15];
values.sort();
alert(values); //0,1,10,15,5

  sort()方法还可以接受一个比较函数作为参数,以便指定哪个值位于哪个值的前面。

  升序:比较函数接受两个参数,如果第一个参数应该位于第二个参数之前则返回一个负数,如果两个参数相等则返回0,如果第一个参数应该位于第二个参数之后则返回一个正数。

  如果是降序,则相反。

//升序
function compare(value1,value2){
if(value1 < value2){ return -1; //如果value1 < value2, 则不需要交换 }else if(value1 > value2){ return 1; //如果value1 > value2, 则需要交换 }else{ return 0; } } var values = [0,1,5,10,15]; values.sort(compare); alert(values); //0,1,5,10,15

  5.2.5 操作方法

  contact()方法:基于当前数组中的所有项创建一个新数组。这个方法先创建当前数组的一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。在没有给contact()方法传递参数的情况下,它只是复制当前数组并返回副本。

var colors = ["red","green","blue"];
var colors1 = colors.concat();
alert(colors1); //red,green,blue, 没有给contact()方法传递参数,只是简单的复制数组
var colors2 = colors.concat("yellow",["black","brown"]);
alert(colors2);//red,green,blue,yellow,black,grown,将参数数组中的每一项都添加到结果数组中。

  slice()方法:如果是一个参数,返回从该参数指定位置开始到当前数组末尾的所有项。

        如果是两个参数,返回起始和结束位置之间的项,但不包括结束位置的项。

var colors = ["red","green","blue","yellow","black","brown"];
var colors1 = colors.slice(1);
alert(colors1); //green,blue,yellow,black,brown  返回从下标为1开始到数组末尾的所有项
var colors2 = colors.slice(1,4);
alert(colors2); //green,blue,yellow  返回从下标为1到下标为3结束的所有项
var colors3 = colors.slice(-2,-1);
alert(colors3);//black 如果slice()方法的参数中有一个负数,则用数组的长度加上该数来确定相应的位置。colors.slice(-2,-1)=colors.slice(4,5)

   splice()方法:

  (1)删除任意数量的项,2个参数:要删除的第一项的位置和要删除的项数。

var colors = ["red","green","blue"];
var removed = colors.slice(0,2);
alert(removed); //red,green

  (2) 插入------可以向指定位置插入任意数量的项。3个参数:起始位置,0(要删除的项数)和要插入的项。如果要插人多个项,可以再传入第四、第五,以致任意多个项。

var colors = ["red","green","blue"];
var removed = colors.splice(1,0,"black","orange");
alert(colors); //red,black,orange,green,blue  在小标为1的地方插入两个项目“black”,“orange”连个项
alert(removed); //空数组

  (3)替换------可以向指定位置插入任意数量的项,且同时删除任意数量的项。3个参数:起始位置、要删除的项数和要插入的任意数量的项。

var colors = ["red","green","blue"];
colors.splice(1,2,"black","orange");
alert(colors); //red,black,orange  从下标为1的地方删除2个项,然后在小标为1的地方插入两个项“black”,“orange”连个项
alert(removed); //green,blue

5.4 RegExp类型

  var expression = /pattern/flags;

  其中的模式(pattern)部分可以是任何简单或复杂的正则表达式。

  每个正则表达式都可带有一个或多个表示(flags),用以表明正则表达式的行为。正则表达式的匹配模式支持下列3个标志:

  g------表示全局(global)模式,即模式被应用于所有字符串,而非在发现第一个匹配项时立即停止。

  i-------表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写。

  m-----表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。

var pattern1 = /at/g; //匹配字符串中所有"at"实例
var pattern2 = /[bc]at/i  //匹配第一个“bat”或"cat",不区分大小写
var pattern3 = /[bc]at/i  //(转义)匹配第一个“[bc]at",不区分大小写
var pattern4= /.at/gi;  //匹配所有以“at”结尾的3个字符的组合,不区分大小写
var pattern4= /.at/gi;  //匹配所有".at”,不区分大小写

  上面的例子都是以字面量形式来定义的正则表达式,另一种创建正则表达式的方式是使用RegExp构造函数,2个参数: 一个是要匹配的字符串模式,另一个是可选的标志字符串。

var pattern1 = /[bc]at/i;
var pattern2 = new RegExp("[bc]at","i"); //与pattern1相同,只不过是使用构造函数创建的

  RegExp对象的主要方法是exec(),该方法是专门为捕获组而设计的。exec()接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配信息的数组。返回的数组虽然是Array的实例,但包含两个额外的属性:index和input。index表示匹配项在字符串中的位置,而input表示正则表达式的字符串。

  对于exec()方法而言,即是在模式中设置了全局模式(g),它每次也只会返回一个匹配项。在不设置全局标志的情况下,在同一个字符串中多次调用exec()将始终返回第一个匹配项的信息。而在设置全局标志的情况下,每次调用exec()则都会在字符串中继续查找新匹配项。如:

var text = "cat, bat, sat, fat";
var pattern1 = /.at/;
        
var matches = pattern1.exec(text);
alert(matches.index); //0, index表示匹配项在字符串中的位置
alert(matches[0]); //cat, 在不设置全局标志的情况下,在同一个字符串上多次调用exec()将始终返回第一个匹配项的信息
alert(pattern1.lastIndex);//3
        
matches = pattern1.exec(text);
alert(matches.index); //0, index表示匹配项在字符串中的位置
alert(matches[0]); //cat, 在不设置全局标志的情况下,在同一个字符串上多次调用exec()将始终返回第一个匹配项的信息
alert(pattern1.lastIndex);//3
        
var pattern2 = /.at/g;
matches = pattern2.exec(text);
alert(matches.index); //0, index表示匹配项在字符串中的位置
alert(matches[0]); //cat, 在设置全局标志的情况下,每次调用exec()都会在字符串中继续查找新匹配项
alert(pattern2.lastIndex);//3
        
matches = pattern2.exec(text);
alert(matches.index); //0, index表示匹配项在字符串中的位置
alert(matches[0]); //bat, 在设置全局标志的情况下,每次调用exec()都会在字符串中继续查找新匹配项
alert(pattern2.lastIndex);//8

  正则表达式的第二个方法是test(),它接受一个字符串参数,在模式与该参数匹配的情况下返回true,否则,返回false。

var text = "000-00-0000";
var pattern = /d{3}-d{2}-d{4}/;
if(pattern.test(text)){
    alert("The pattern was matched");
}

  5.4.3 RegExp构造函数属性

  RegExp构造函数包含一些属性,这些属性在调用exec()或test()方法时,这些属性会被自动填充。

  注:Opera不支持input、lastMatch、lastParen和multiline属性

    IE不支持multiline属性

var text = "this has been a short summer";
var pattern = /(.)hort/g;//匹配任何一个字符后跟hort,而且把第一个字符放在了一个捕获组中。
        
if(pattern.test(text)){
    alert(RegExp.input); //this has been a short summer,最近一次要匹配的字符串。
    alert(RegExp.lastMatch);//short, 属性返回最近一次与整个正则表达式匹配的字符串
    alert(RegExp.leftContext); //this has been a  ,input字符串中lastMatch之前的文本
    alert(RegExp.rightContext); //summer,input字符串中lastMatch之后的文本
    alert(RegExp.lastParen); //s, 属性返回最近一次匹配的捕获组,即例子中的“s”
    alert(RegExp.multiline); //布尔值,表示是否所有表达式都使用多行模式。IE和opera未实现此模式
}

   5.5.3 作为值的函数

  要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号。

  根据某个对象属性对数组进行排序。

function createComparisonFunction(propertyName){
            
    return function(object1,object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if(value1 < value2){
            return -1;
        }else if(value1 > value2){
            return 1;
        }else{
            return 0;
        }
    };
}
        
var data = [{name:"Zara",age:28},{name:"Nike",age:29}];
data.sort(createComparisonFunction("age"));
alert(data[0].name);

  5.5.4 函数内部属性

  在函数内部,有2个特殊的对象:arguments和this。arguments是一个类数组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫calllee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

function factorial(num){
    if(num <= 1){
        return 1;
    }else{
        return num * factorial(num-1);  //这个函数的问题是:这个函数的执行与函数名factorial紧紧耦合在一起。
    }
}
//等价于下面这个函数
function factorial(num){
    if(num <= 1){
        return 1;
    }else{
        return num * arguments.callee(num-1);//这样消除了耦合。
    }
}
        
alert(factorial(5)); //120;
var trueFactorial = factorial;
    factorial = function(){
        return 0;
};
alert(trueFactorial(5)); //120
alert(factorial(5)); //0

  5.5.5 函数属性和方法

  ECMAScript中的函数是对象,因此函数也有属性和方法,每个函数都包含两个属性:length和prototype。其中,length属性表示函数希望接收的命名参数的个数。如:

function sayName(name){
    alert(name);
}
function sum(num1,num2){
    return num1 + num2;
}
alert(sayName.length); //1
alert(sum.length); //2

  每个函数都包含2个非集成而来的方法:apply()和call()。apply()和call()真正的用武之地是能够扩充函数赖以运行的作用域:

window.color = "red";
var o = {color : "blue"};
        
function sayColor(){
    return this.color;
}
        
alert(sayColor()); //sayColor()是在全局作用域中定义的,this引用的是全局对象window。
alert(sayColor.call(this)); //red, this.color转换成window.color
alert(sayColor.call(window)); //red
alert(sayColor.call(o)); //blue, this.color转换成o.color

 15.7.8 复制节点

  cloneNode()方法可以复制节点。此方法只有一个布尔类型的参数,true或false,参数是可选的。则只对该节点及其属性进行复制,不涉及任何子节点(这意味着它不会复制任何文字)。如果该值被设置为true(深度复制),那么所有子节点也都会被复制。因为id必须是唯一的,所以如果复制有id属性的元素,就必须自己为复制节点赋id值。

var p1 = document.getElementById("para1");
var oldPara = p1.firstChild;
var newPara = oldPara.cloneNode(false);//复制P中的文字
p1.appendChild(newPara);

  复制节点属性。

var p1 = document.getElementById("para1");
var p2 = document.getElementById("para2");
var p1Style = p1.getAttributeNode("style");
var cloneP1Style = p1Style.cloneNode(true);//复制节点属性
p2.setAttributeNode(cloneP1Style);

  删除节点。

var divMid = document.getElementsByTagName("div")[1];
divMid.parentNode.removeChild(divMid);

   利用节点实现文本滚动

window.onload = function(){
      divElement = document.getElementById("div1");
      scroller();
 };
function scroller(){
      window.setTimeout('scroller()',scroll_speed);
      var msg = divElement.firstChild.nodeValue;
      divElement.firstChild.nodeValue = msg.substring(chars) + msg.substring(0,chars);
}

  停止或取消事件流

  stopPropagation()停止事件流中事件的进一步传播。(也就是取消冒泡)

  preventDefault()取消可取消的事件,意味着事件发生时的默认操作是不会被取消的。

  e.cancelBubble = true;在IE中取消事件的冒泡。

    window.onload = function(){
              var body1 = document.getElementById("body1");
              var div1 = document.getElementById("div1");
              var para1 = document.getElementById("para1");
              var para2 = document.getElementById("para2");
              var a1 = document.getElementById("link1");
              
              body1.onclick = iam;
              div1.onclick = iam;
              para1.onclick = iam;
              para2.onclick = iam;
              a1.onclick = iam;
          };
          
          function iam(e){
              alert(this.id);
              if(!e){
                  e = window.event;
                  e.cancelBubble = true;
              }else{
                  e.stopPropagation(); //取消事件冒泡。如果不取消事件冒泡,则会打印link1->para1->div1->body1。取消了事件冒泡以后只打印link1。
              }
          };

  注册事件

paraHandler1.addEventListener("mouseover",highLight,false);//鼠标经过会触发highLight()函数 ,true表示开启事件捕获,false开启事件冒泡,跨浏览器兼容性最强的方式是false。
paraHandler2.addEventListener("click",function(){ this.style.fontSize = "x-large"; },false);
function highLight(){
  this.style.backgroundColor = "tan";
  this.style.fontFamily = "fantasy";
  this.style.fontWeight = "bold";
}

  删除事件

paraHandler1.removeEventListener("mouseover",highLight,false);

  IE的事件监听

      if(window.attachEvent){
              window.attachEvent("onload",greeting_load);
              document.attachEvent("onclick",greeting_click);
              document.attachEvent("onmouseover",greeting_mouseover);
          }else{
              window.addEventListener("load",greeting_load,false);
              document.addEventListener("click",greeting_click,false);
              document.addEventListener("mouseover",greeting_mouseover,false);
          }
          if(window.detachEvent){
              document.detachEvent("onmouseover",greeting_mouseover);    
          }else{
              document.removeEventListener("mouseover",greeting_mouseover,false);
         }

  事件属性:

  currentTarget : 目前正在被处理函数处理的节点(IE不支持)

  srcElement : 指触发事件的标签对象(只在IE中适用)

  target : 事件发生的节点,它不一定同currentTarget一样

  timeStamp : 事件发生的时间

  type : 发生的事件的类型,如click或mouseout

      window.onload = function(){
              var div1 = document.getElementById("first");
              if(div1.addEventListener != undefined){
                  div1.addEventListener("mouseover",colorText,false);
                  div1.addEventListener("mouseout",noColorText,false);
              }else{
                  //IE
                  div1.attachEvent("onmouseover",colorText);
                  div1.attachEvent("onmouseout",noColorText);
              }
          };
          function colorText(e){//e是事件发生的对象的引用
              var evt = e || window.event;
              var evtTarget = evt.target || evt.srcElement;
              if(evtTarget.id == "first"){
                  evtTarget.className = "red";
              }
          }

 16、 cookie

  escape()函数会对字符串进行编码,把所有的非字母数字符号转换成其对应的16进制数字,在前面加上%。例如%20代表空格,%26代表&。

  unescape()函数把URI编码后的字符串转换为原始格式并返回。

  encodeURI()和decodeURI()内建函数是escape()和unescape()函数的最新版本,支持编码的字符变少了。 

 14、常用的样式表属性

  font-style : normal(正常) | italic(斜体) | oblique(倾斜)

  font-varient  : 设置小型大写字母的字体显示文本,这意味着所有的小写字母均会被转换为大写,但是所有使用小型大写字体的字母与其余文本相比,其字体尺寸更小.

      取值 :  normal | small-caps 

  background-attachment : fixed | scroll 设置背景图像是否固定或者随着页面的其余部分滚动

    letter-spacing 属性增加或减少字符间的空白(字符间距)。取值 : normal | 0.1em | 0.2em | ...

  line-height 属性设置行间的距离(行高)normal | 1.2 | 1.2em | 120%

  text-decoration : underline | overline | line-through | blink

  text-transform : capitalize(将每个单词的第一个字母转换成大写,其余无转换发生) | uppercase(转换成大写) | lowercase(转换成小写) | none

  text-indent : 文本块中首行文本的缩进 3em | 15%......

  vertical-align : baseline(默认。元素放置在父元素的基线上) | sub(垂直对齐文本的下标) | super(垂直对齐文本的上标) | top(把元素的顶端与行中最高元素的顶端对齐)

         | text-top(把元素的顶端与父元素字体的顶端对齐) | middle(把此元素放置在父元素的中部) | bottom(把元素的顶端与行中最低的元素的顶端对齐)

           | text-bottom(把元素的底端与父元素字体的底端对齐) | length() | %(使用 "line-height" 属性的百分比值来排列此元素。允许使用负值) 

  word-spacing : 属性增加或减少单词间的空白(即字间隔)取值:normal | 2em。与letter-spacing的区别:letter-spacing是在每个字符间都加空白,而word-spacing是在每个单词  间加空白。

  border-width : medium(默认宽度) | thin(小于默认宽度) | thick(大于默认宽度) | 10px......

  border-style : solid | dashed | dotted | double | groove | ridge | inset | outset

  border-collpase : collapse(边框合并) | separate(默认值。边框会被分开)

 14.11.11 JavaScript如何操作样式表

  document.styleSheets[0]是第一个样式表,document.styleSheets[1]是第二个样式表,等等。

  styleSheets数组中的每个元素都有一个disabled属性,用于开启和关闭元素功能。用户也可以使用W3C cssRules数组或Microsoft rules数组访问样式表中的具体规则。第一条规则是cssRules[0], 第二条规则是cssRule[1]。

      <style type="text/css">
       @import url("pstyle.css"); //第一个样式表,document.styleSheets[0]
      </style>
      <style type="text/css">
          p{  //第二个样式表,document.styleSheets[1]
              background-color : darkblue;
              font-weight : bold;
              font-size : 12pt;
              font-family : arial;
              color : yellow;
          }
          h1{
              color : red; //document.styleSheets[1].cssRules[1].style
          }
      </style>
      <script type="text/javascript">
          function changeStyle(){
              document.styleSheets[0].disabled = false;
              document.styleSheets[1].disabled = true;
          }
          function enableOldStyle(){
              document.styleSheets[0].disabled = true;
              if(document.styleSheets[1].cssRules){
            //W3C
                  document.styleSheets[1].cssRules[1].style.color = "purple";
              }else{
                  //IEdocument.styleSheets[1].rules[1].style.color = "purple";
              }
              document.styleSheets[1].disabled = false;
          }
      </script>    

  

原文地址:https://www.cnblogs.com/hardworkingbee/p/4547365.html