《JavaScript高级程序设计》(第三版)这本红皮书应该是很有名了,买这本有一年了,断断续续的看了前七章,收获很多。趁着周末,刚好把之前记的纸质笔记记录到简书上。
1、如果在函数中使用var
定义一个变量,是局部变量,如果省略了var
就是全局变量。
function test() {
var message = "hi"; //局部变量
}
test();
alert(message);//报错
function test2() {
message2 = "hi";//全局变量
}
test2();
alert(message2);//hi
2、五种基本数据类型:Undefined Null Boolean Number String,还有一种复杂数据类型Object。
3、typeof
:检测给定变量的数据类型。
typeof null //object
4、Undefined类型:使用var
声明变量,但为对其初始化时。
5、Null类型:只有一个值null。空对象指针。如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null,这样只要检查null值就可以知道相应的变量是否已经保存了一个对象的引用。
var car = null;
if(car!=null) {
对car对象执行某些操作
}
alert(undefined==null);//true
6、Boolean类型:有两个值true和false,这两个值与数字值不是一回事,因此true不一定等于1,而false不一定等于0。对任何数据类型的值调用 Boolean()
函数,而且总会返回一个Boolean
值。
Boolean(0);//false
Boolean("");//false
Boolean(NaN);//false
Boolean(undefined);//false
Boolean(null);//false
7、NaN:非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数为返回数值的情况。任何数值除以非数值会返回NaN。NaN与任何值都不相等,包括NaN本身。
8、数值转换:有三个函数可以把非数值转换为数值:Number()、parseInt()和parseFloat(),第一个函数可以用于任何数据类型,而另外两个函数则专门用于把字符串转换成数值。
Number(true);//1
Number(false);//0
Number(null);//0
Number(undefined);//0
Number("123");//123
Number("011");//11
Number("");//0
Number("hi");//NaN
parseInt("1234blue");//1234
parseInt("");//NaN
parseInt(22.5);//22
parseFloat("1234blue");//1234
parseFloat("0xA");//0
parseFloat("22.5");//22.5
parseFloat("22.5.5");//22.5
9、String类型:
String(null);//"null"
String(undefined);//"undefined"
10、Object类型:创建Object实例的方式有两种,第一种是使用new操作符后跟object构造函数,第二种是对象字面量表示,Object的每个实例都具有下列属性和方法:
var o = new Object();
var person = {
name:"kele",
age:18
}
constructor
:保存着用于创建当前对象的函数,上面例子,constructor就是Object()。
hasOwnProperty(propertyName)
:用于检查给定的属性在当前对象实例中(而不是实例的原型中)是否存在。o.hasOwnProperty("name")
。
isPrototypeOf(object)
:用于检查传入的对象是否是当前对象的原型。
propertyIsEnumberable(propertyName)
:用于检查给定的属性是否能够使用for-in
语句来枚举。
toLocalString()
:返回对象的字符串表示。
toString()
:返回对象的字符串表示。
valueOf()
:返回对象的字符串、数值或布尔值表示。
11、逻辑与:逻辑与操作可以用于任何类型的操作数,而不仅仅是布尔值。在有一个值不是布尔值的情况下,逻辑与操作就不一定返回布尔值,此时遵循下列规则:
- 如果第一个操作数是对象,则返回第二个操作数;
- 如果第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象。
- 如果两个操作数都是对象,则返回第二个操作数。
- 如果第一个操作数是null,则返回null。
- 如果第一个操作数是NaN,则返回NaN。
- 如果第一个操作数是undefined,则返回undefined。
逻辑与操作属于短路操作,如果第一个操作数能够决定结果,那么就不会再对第一个操作数求值。
var a = true;
var result = a && b;/会报错,因为b未声明
alert(result);//这一行不会执行
var b = false;
var c = b && d;
alert(c);//false
12、逻辑或:
- 如果第一个操作数是对象,则返回第一个操作数。
- 如果第一个操作数的求值结果为false,则返回第二个操作数。
- 如果两个操作数都是对象,则返回第一个操作数;
- 如果两个操作数都是null,则返回null。
- 如果两个操作数都是NaN,则返回NaN。
- 如果两个操作数都是undefined,则返回undefined。
逻辑或操作符是短路操作,如果第一个求值的结果是为true,就不会对第二个操作数求值了。
var a = true;
var result = a || b;
alert(result);//true
var b = false;
var c = b || d;//报错
alert(c);//不执行
13、break和continue语句:break语句立即退出循环强制继续执行循环后面的语句,而continue会退出循环之后会从循环的顶部继续执行。
var num = 0;
for(var i=1;i<10;i++){
if(i%5==0) {
break;
}
num++
}
alert(num);//4
var num =0;
for(var i=1;i<10;i++){
if(i%5==0){
continue;
}
num++;
}
alert(num);//8
14、函数:用function
关键字来声明,函数会在执行完return
语句之后停止并立即退出,return
之后的任何代码永远不会执行。函数体内可以通过arguments
对象访问参数数组,从而获取传递给函数的每一个参数。可以向函数传递任意数量的参数。
function howManyArgs() {
alert(arguments.length);
}
howManyArgs("string",45);//2
howManyArgs();//0
arguments
对象中的值会自动反映到对应的命名参数上。
function test(num1,num2) {
arguments[1]=10;
alert(arguments[0]+num2);
}
每次执行test()函数都会重写第二个参数,将第二个参数修改为10,因为arguments对象中的值会自动反映到对应的命名参数,所以修改arguments[1]
,也就修改了num2
。这并不是说读取这两个值会访问相同的内存空间;它们的内存空间是独立的,但它们的值会同步。如果只传入了一个参数,那么为arguments[1]
设置的值不会反映到命名参数中,因为arguments对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。
未指定返回值的函数返回的是一个特殊的undefined。
15、函数没有重载,定义了两个名字相同的函数,则该名字只属于后定义的函数。
function test(num) {
return num+100;
}
function test(num) {
return num+200;
}
var result = test(100); //300
16、变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,引用类型指的是由多个值构成的对象。
17、复制变量值:引用类型和基本类型值除了保存的方式不同之外,在从一个变量向另一个变量复制时,也存在不同。如果从一个变量向另一个变量复制基本数据类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
var num1 = 5;
var num2 = num1;
在num1中保存的是5,当使用num1初始化num2时,num2中也保存了5。但num2中的5与num1中的5是完全独立的。
当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象的值复制一份放到新变量分配的空间中。不同的是,这个值的副本是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量。
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "kele";
alert(obj2.name);//kele
18、传递参数:ECMAScript中所有函数的参数都是按值传递的。把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。
function test(num){
num += 10;
return num;
}
var count = 20;
var result = test(count);
alert(count);//20 没有变化
alert(result);//30
function setName(obj) {
obj.name = "kele";
}
var person = new Object();
setName(person);
alert(person.name);//"kele"
function setName2(obj) {
obj.name = "hi";
obj = new Object();//引用的局部对象
obj.name = "hello";
}
var person2 = new Object();
setName2(person2);
alert(person2.name);//"hi"
19、instanceof:检测引用类型的值。在检测一个引用类型值和Object构造函数时,instanceof操作数始终会返回true。如果检测基本数据类型的值,则返回false。
alert(a instanceof Object);
alert(a instanceof Array);
20、垃圾收集:javascript具有自动垃圾收集机制,javascript中最常用的垃圾收集方式是标记清除。另一种叫做引用计数。
21、执行环境有全局执行环境和函数执行环境,全局环境只能访问在全局环境中的变量和函数,局部环境不仅有权访问函数作用域中的变量,还可以访问包含父环境乃至全局环境。
22、使用不带圆括号的函数名是访问函数指针,而非调用函数。
function sum(num1,num2){
return num1 + num2;
}
alert(sum(10,10));//20
var anotherSum = sum;
alert(anotherSum(10,10));//20
sum=null;
alert(anotherSum(10,10));//20
23、函数声明与函数表达式的区别:解析器会率先读取函数声明,并使其在执行任何代码之前可以调用,函数表达式则必须等到解析器执行到它所在的代码行,才会真正被执行。
alert(sum(10,10));//20 正常执行
function sum(num1,num2) {
return num1+num2;
}
alert(test(20,20));//会报错
var test = function(num1,num2) {
return num1+num2;
}
24、作为值的函数:不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。例如,假设有一个对象数组,我们想要根据某个对象属性对数组进行排序。而传递给数组sort()
方法的比较函数要接收两个参数,即要比较的值。可是,我们需要一种方式来指明按照哪个属性来排序。要解决这个问题,可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数。
function createCompareFunction(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:"Zachary",age:28},{name:"Nicholas",age:29}];
data.sort(createCompareFunction("name"));
alert(data[0].name);//Nicholas
data.sort(createCompareFunction("age"));
alert(data[0].name);//Zachary
25、函数内部属性:函数内部有两个特殊的对象:arguments和this。其中,arguments
是一个类数组对象,包含着传入函数中的所有参数。这个对象还有一个callee
的属性,该属性是一个指针,指向拥有这个arguments
对象的函数。
function test(num) {
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
var test2 = test;
test = function() {
return 0;
}
alert(test2(5));//120
alert(test(5));//0
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//"red"
o.sayColor();//blue
函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境变量中执行,全局的sayColor()函数
25、ECMAScript5规范了函数对象的属性:caller
。这个属性中保存着调用当前函数的函数的引用,如果是在全局函数中调用当前函数,它的值为null。
function outer(){
inner();
}
function inner(){
alert(inner.caller);
}
outer();
以上代码会导致警告框中显示outer()
函数的源代码。因为outer()
调用了inner()
,所以inner.caller
就指向了outer()
。也可以通过arguments.callee.caller
来访问相同的信息。
function outer() {
inner();
}
function inner() {
alert(arguments.callee.caller);
}
outer();
当函数在严格模式下运行,访问 arguments.callee
和arguments.caller
会导致错误。严格模式下不能为caller属性赋值,否则会导致错误。
26、ECMAScript
中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length
和prototype
。length
属性表示函数希望接收的命名参数的个数。
function sayName(name){
alert(name);
}
function sum(num1,num2){
return num1+num2;
}
function sayHi(){
alert("hi");
}
alert(sayName.length);//1
alert(sum.length);//2
alert(sayHi.length);//0
27、对ECMAScript
中的引用类型,prototype
是保存它们所有实例方法的真正存在,toString()
方法和valueOf()
等方法都保存在prototype
中,通过各自对象的实例访问。ECMAScript5
中,prototype
属性是不可枚举的。
28、每个函数都包含两个非继承而来的方法:apply()
和call()
。两个方法的用途都是在特殊作用域中调用函数,实际上等于设置函数体内this
对象的值。首先apply()
方法接收两个参数:一是在其中运行函数的作用域,另一个是函数数组。其中,第二个参数可以是Array
的实例,也可以是arguments
对象。
function sum(num1,num2){
return num1+num2;
}
function callSum1(num1,num2){
return sum.apply(this,arguments);//传入arguments对象
}
function callSum2(num1,num2){
return sum.apply(this,[num1,num2]);//传入数组
}
alert(callSum1(10,10));//20
alert(callSum2(10,10));//20
29、call()
方法与apply()
方法的作用相同,它们的区别仅在于接收参数的方式不同。对象call()
方法,第一个参数是this
没有变化,变化的是其余参数都直接传递给函数。在使用call()
方法时,传递给函数的参数必须逐个列举出来。
function sum(num1,num2){
return num1+num2;
}
function callSum(num1,num2){
return sum.call(this,num1,num2);
}
alert(callSum(10,10));//20
传递参数并非apply()
和call()
真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue
30、ECMAScript5
还定义了一个方法:bind()
。这个方法会创建一个函数的实例,其this
值会被绑定到传给bind()
函数的值。
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor();//blue
这些是看这本书的前六章的笔记,后面还会记录之后几章的笔记。买的尤克里里回来了,买的苹果电脑也到了,双十一什么也没买,但是依然要吃吐了,捂脸。。。
要多看书,多写笔记,多敲代码,要不然都对不起这么贵的MacBook Pro....
网友评论