JavaScript高级程序设计(第3版)读书笔记

2018.3.30

1.有3个函数可以把非数值转换为数值:

Number():可用于任何数据类型

parseInt()和parseFloat():专门用于把字符串转换为数值

2.逻辑与操作属于短路操作,即如果第一个操作数能决定结果,那么就不会再对第二个操作数求值。

eg:var found=true;

var result=(found&&someUndefinedVariable);//这里会发生错误

alert(result);//这一行不会执行

在上面的代码中,当执行逻辑与操作时会发生错误,因为变量someUndefinedVariable没有声明。

var found=false;

var result=(found&&someUndefinedVariable);//这里不会发生错误

alert(result);//会执行(“false”)

在这个例子中,警告框会显示出来。无论变量someUndefinedVariable有没有定义,也永远不会对它求值,因为第一个操作数的值是false。而这也就意味着逻辑与操作的结果必定是false,根本用不着再对&&右侧的操作数求值了。在使用逻辑与操作符时始终铭记它是一个短路操作符。

3.逻辑或也是短路操作符。

我们可以利用逻辑或的这一行为来避免为变量赋null或undefined值。例如:

var myObject=perferredObject||backupObject;

在这个例子中,变量myObject将被赋予等号后面两值中的一个。变量perferredObject中包含优先赋给变量myObject的值,变量backupObject负责在perferredObject中不包含有效值的情况下提供后备值。如果perferredObject的值不是null,那么它的值将被赋给myObject;如果是null,则将backupObject的值赋给myObject。

3.31

4.ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript函数不介意传递进来多少参数,也不在乎传递进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数。

因为ECMAScript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。实际上,在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

其实,arguments对象只是与数组类似(它并不是Array的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0],第二个是arguments[1],以此类推),使用length属性来确定传递进来多少个参数。

不显式地使用命名参数:

function sum(){

alert(arguments[0]+arguments[1]);

}

sum(2,3);

这个函数不包含命名的参数。虽然没有使用num1,num2标识符,但函数功能完成。这说明ECMAScript函数的一个重要特点:命名的参数只是提供便利,但不是必须的。另外,在命名参数方面,其它语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致。但在ECMAScript中,没有这些条条框框,解释器不会验证命名参数。


5.ECMAScript函数不能像传统意义上那样实现重载。而在其他语言(如java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScript函数没有签名,因为其参数是由包含零或多个值得数组来表示的。而没有签名,真正的重载是不可能做到的。

如果在ECMAScript中定义了两个名字相同的函数,则改名字只属于后定义的函数。eg:

function addSomeNumber(num){

return num+100;

}

function addSomeNumber(num){

return num+200;

}

var result=addSomeNumber(100);   //300

后定义的函数覆盖了先定义的函数。

6.引用类型的值是保存在内存中的对象。与其它语言不同,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。

在很多语言中,字符串以对象的形式来表示,因此被认为是引用类型的。ECMAScript放弃了这一传统。

7. 基本类型和引用类型

(1)定义基本类型值和引用基本类型值的方式是类似的:创建一个变量并为该变量赋值。

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

var person=new object();

person.name="Nicholas";

alert(person.name);   //"Nicholas"

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

var name="Nicholas";

name.age=27;

alert(name.age);  //undefined

说明只能给引用类型值动态地添加属性,以便将来使用。

(2)除了保存的方式不同之外,在从一个变量向另一个变量复制基本类型值和引用类型值时,也存在不同。eg:

var num1=5;

var num2=num1;

num1和num2的5是完全独立的,此后,这两个变量可以参与任何操作而不会相互影响。

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

var obj1=new Object();

var obj2=obj1;

obj1.name="Nicholas";

alert(obj2.name);  //"Nicholas"

8.访问变量有按值和按引用两种方式,而参数只能按值传递。

可以把ECMAScript函数的参数想象成局部变量。

四月一日

9.如果变量的值是一个对象或null,则typeof操作符返回"object"

虽然在检测基本数据类型时,typeof是得力的助手,但检测引用类型的值时,我们用instanceof操作符。eg:

alert(person instanceof Object);

alert(colors instanceof Array);

alert(pattern instanceof RegExp);

如果使用instanceof操作符检测基本类型的值,则操作符始终会返回false,因为基本类型不是对象。

10.JavaScript没有块级作用域

11.创建Object实例的方式有两种。

(1)使用new操作符后跟Object构造函数

var person=new Object();

person.name="Nicholas";

person.age=29;

(2)使用对象字面量表示法

var person={

name:"Nicholas",

age:29

};

在使用对象字面量语法时,属性名也可以使用字符串,eg:

var person={

"name":"Nicholas",

"age":29,

5:true

};

另外,使用对象字面量语法时,如果留空其花括号,则可以定义只包含默认属性和方法的对象,eg:

varr person{};   //与new Object()相同

person.name="Nicholas";

person.age=29;

			function displayInfo(args){
				var output="";
				if(typeof args.name=="string"){
					output+="Name:"+args.name+"\n";
				}
				if (typeof args.age=="number"){
					output+="Age:"+args.age+"\n";
				}
				alert(output);
			}
			displayInfo({
				name:"Nicholas",
				age:29
			});
			displayInfo({
				name:"zhouzy"
			});
			//在这个例子中,函数displayInfo()接受一个名为args的参数。这个参数可能带有一个名为name或age的属性,也可能这两个属性都要或者都没有。在这个函数内部,我们通过typeof操作符来检测每个属性是否存在,然后再基于相应的属性来构建一条要显示的消息。然后,我们调用了两次这个函数,每次都使用一个对象字面量来指定不同的数据。这两次调用传递的参数虽然不同,但函数都能正常执行。

一般来说,访问对象属性时使用的都是点表示法。不过,在JavaScript也可以使用方括号表示法来访问对象的属性。eg:

alert(person["name"]);     //"Nicholas"

alert(person.name);        //"Nicholas"

从功能上看,这两种访问对象属性的方法没有任何区别。但方括号的优点是可以通过变量来访问属性,eg:

var propertyName="name";

alerrt(person[propertyName]);       //"Nicholas"

如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以使用方括号表示法。eg:

person["first name"]="Nicholas";

由于first name中包含一个空格,所以不能用点表示法来访问它。然而,属性名中是可以包含非字母非数字的,这时候就可以使用方括号表示法来访问它们。

12.创建数组的基本方式有两种

(1)使用Array构造函数。eg:

var colors=new Array();

var colors=new Array(20);

var colors=new Array("red","blue","green");

另外,在使用Array构造函数时也可以省略new操作符。

(2)使用数组字面量表示法。数组字面量由一对包含数组项的方括号表示,多个数组项之间以逗号隔开,eg:

var colors=["red","blue","green"];

13.利用length属性可以方便的在数组末尾添加新项。eg:

var colors=["red","blue","green"];        //创建一个包含3个字符串的数组

colors[colors.length]="black";        //在位置3添加一种颜色

colors[colors.length]="brown";        //在位置4再添加一种颜色

由于数组最后一项的索引始终是length-1,因此下一个新项的位置就是length。

var colors["red","blue","green"];        //创建一个包含3个字符串的数组

colors[99]="black";        //在位置99添加一种颜色

alert(colors.length);        //100

在这个例子中,我们向colors数组的位置99插入了一个值,结果数组新长度(length)就是100(99+1)。而位置3到位置98实际上都是不存在的,所以访问它们都将返回undefined。

14.所有对象都具有toLocaleString()、toString()和valueof()方法。

数组继承的toLocaleString()、toString()和valueOf()方法,在默认情况下都会以逗号分隔的字符串的形式返回数组项。而如果使用join()方法,则可以使用不同的分隔符来构建这个字符串。join()方法只接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的字符串。eg:

var colors["red","green","blue"];

alert(colors.join("||"));            //red||green||blue

四月二号

15.indexOf()方法接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。

注:它位置的索引不会变。eg:

var numbers=[1,2,3,4,5,4,3,2,1];

alert(numbers.indexOf(5);          //4

alert(numbers.indexOf(5,2);          //4

alert(numbers.indexOf(5,3);            //4

16.正则表达式

eg:匹配第一个“bat”或"cat",不区分大小写

(1)字面量形式

var pattern1=/[bc]at/i;

(2)通过构造函数创建

var pattern2=new RegExp("[bc]at","i");

17.作为值的函数

function callSomeFunction(someFunction,someArgument){

return someFunction(someArgument);

}

//从一个函数中返回另一个函数
//有一个数组,我们想要根据某个对象属性对数组进行排序。而传递给数组sort()方法的比较函数要接收两个参数,即要比较的值。可是,我们需要一种方式来指明按照哪个属性来排序。要解决这个问题,可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数,下面就是这个函数的定义。
function createComparisonFunction(propertyName){
	return function (object1,object2){
		var value1=object1[propertyName];
		var value2=object2[propertyName];
		return(value1-value2);
	};
}
var data=[{name:"zhouzy",age:20},{name:"hujy",age:19}];
data.sort(createComparisonFunction("name"));
alert(data[0].name);
data.sort(createComparisonFunction("age"));
alert(data[0].name);

18.在函数内部,有两个特殊的对象:arguments和this.

ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript函数不介意传递进来多少参数,也不在乎传递进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数。

因为ECMAScript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。实际上,在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

其实,arguments对象只是与数组类似(它并不是Array的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0],第二个是arguments[1],以此类推)。

arguments是一个类数组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

// //arguments是一个类数组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。请看下面这个非常经典的阶乘函数。
// function factorial(num){
// 	if(num<=1){
// 		return 1;
// 	}else{
// 		return num*factorial(num-1)
// 	}
// }
// //定义阶乘函数一般都要用到递归算法;如上面的代码所示,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名factorial紧紧耦合在了一起。为了消除这种紧密耦合的现象,可以像下面这样使用arguments.callee.
// function factorial(num){
// 	if(num<=1){
// 		return 1;
// 	}else{
// 		return num*arguments.callee(num-1)
// 	}
// }
// //在这个重写后的factorial()函数体内,没有再引用函数名factorial。这样,无论引用函数时使用的是什么名字,都可以保证正常完成递归调用。eg:
// var trueFactorial=factorial;
// factorial=function(){
// 	return 0;
// };
// alert(trueFactorial(5));
// alert(factorial(5));
//函数内部的另一个特殊对象是this,其行为与java和c#中的this大致类似。换句话说,this引用的是函数据以执行的环境对象——或者也可以说是this的值(当在网页的全局作用域中调用函数时,this对象引用的就是window)。来看下面的例子。
window.color="red";
var o={color:"blue"};
function sayColor(){
	alert(this.color);
}
sayColor();		//red
o.sayColor=sayColor;		//blue
o.sayColor();
//上面这个函数sayColor()是在全局作用域中定义的,它引用了this对象。由于在调用函数之前,this的值并不确定,因此this可能会在代码执行过程中引用不同的对象。当在全局作用域中调用SayColor()时,this引用的是全局对象window;换句话说,对this.color求值会转换成对window.color求值,于是就返回red。而当把这个函数赋值给对象o并调用o.sayColor()时,this引用的是对象o,因此对this.color求值会转换成对o.color求值,结果就返回了blue.
函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的sayColor()函数与o.sayColor()指向的仍然是同一个函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值